diff --git a/BeefySysLib/util/Array.h b/BeefySysLib/util/Array.h index c5241db5..6781e333 100644 --- a/BeefySysLib/util/Array.h +++ b/BeefySysLib/util/Array.h @@ -1080,6 +1080,26 @@ public: return NULL; return &this->mVals[this->mSize - addSize]; } + + template + int BinarySearchAlt(const TAlt& val, const std::function& func) + { + int lo = 0; + int hi = this->mSize - 1; + + while (lo <= hi) + { + int i = (lo + hi) / 2; + const T& midVal = this->mVals[i]; + int c = func(midVal, val); + if (c == 0) return i; + if (c < 0) + lo = i + 1; + else + hi = i - 1; + } + return ~lo; + } }; template > diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 0d4ccea1..0b3ba082 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -225,6 +225,7 @@ namespace IDE Add("Comment Toggle", new => gApp.[Friend]CommentToggle, .Editor); Add("Compile File", new => gApp.Cmd_CompileFile); Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true, true); }); + Add("Debug Comptime", new => gApp.DebugComptime); Add("Debug Normal Tests", new () => { gApp.[Friend]RunTests(false, true); }); Add("Delete All Right", new => gApp.[Friend]DeleteAllRight); Add("Duplicate Line", new () => { gApp.[Friend]DuplicateLine(); }); diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index 54b7e278..c20213f3 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Diagnostics; using Beefy.utils; using IDE.util; +using IDE.Compiler; namespace IDE.Debugger { @@ -80,7 +81,8 @@ namespace IDE.Debugger Optimized = 1, HasPendingDebugInfo = 2, CanLoadOldVersion = 4, - WasHotReplaced = 8 + WasHotReplaced = 8, + HadError = 0x10 } //[Flags] @@ -142,6 +144,9 @@ namespace IDE.Debugger [CallingConvention(.Stdcall),CLink] static extern bool Debugger_OpenFile(char8* launchPath, char8* targetPath, char8* args, char8* workingDir, void* envBlockPtr, int32 envBlockLen, bool hotSwapEnabled); + [CallingConvention(.Stdcall),CLink] + static extern bool Debugger_ComptimeAttach(void* bfCompiler); + [CallingConvention(.Stdcall),CLink] static extern bool Debugger_Attach(int32 processId, AttachFlags attachFlags); @@ -371,6 +376,7 @@ namespace IDE.Debugger public bool mIsRunning; public bool mIsRunningCompiled; public bool mIsRunningWithHotSwap; + public bool mIsComptimeDebug; //public RunState mLastUpdatedRunState; public bool mCallStackDirty; public int32 mActiveCallStackIdx; @@ -427,11 +433,21 @@ namespace IDE.Debugger DeleteAndNullify!(mRunningPath); mRunningPath = new String(launchPath); + mIsComptimeDebug = false; mIsRunningCompiled = isCompiled; mIsRunningWithHotSwap = hotSwapEnabled; return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length, hotSwapEnabled); } + public bool ComptimeAttach(BfCompiler compiler) + { + mIsComptimeDebug = true; + mIsRunningCompiled = false; + mIsRunningWithHotSwap = false; + mIsRunning = true; + return Debugger_ComptimeAttach(compiler.mNativeBfCompiler); + } + public void SetSymSrvOptions(String symCacheDir, String symSrvStr, SymSrvFlags symSrvFlags) { Debugger_SetSymSrvOptions(symCacheDir, symSrvStr, (int32)symSrvFlags); @@ -439,7 +455,9 @@ namespace IDE.Debugger public bool OpenMiniDump(String file) { + mIsComptimeDebug = false; mIsRunningCompiled = false; + mIsRunningWithHotSwap = false; return Debugger_OpenMiniDump(file); } @@ -482,6 +500,9 @@ namespace IDE.Debugger if (breakpoint.mThreadId != -1) breakpoint.mThreadId = 0; } + + mIsComptimeDebug = false; + mIsRunning = false; } public RunState GetRunState() @@ -1083,6 +1104,9 @@ namespace IDE.Debugger public bool Attach(Process process, AttachFlags attachFlags) { + mIsRunningCompiled = false; + mIsComptimeDebug = false; + mIsRunningWithHotSwap = false; return Debugger_Attach(process.Id, attachFlags); } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 042cc537..5d3c8c12 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -862,7 +862,8 @@ namespace IDE let sourceViewPanel = GetActiveSourceViewPanel(); if (sourceViewPanel != null) { - Path.GetDirectoryPath(sourceViewPanel.mFilePath, fullDir); + if (sourceViewPanel.mFilePath != null) + Path.GetDirectoryPath(sourceViewPanel.mFilePath, fullDir); } else if ((gApp.mDebugger.mRunningPath != null) && (!mWorkspace.IsInitialized)) { @@ -4342,7 +4343,10 @@ namespace IDE if (mExecutionQueue.Count == 0) { mOutputPanel.Clear(); - OutputLine("Compiling..."); + if (mDebugger?.mIsComptimeDebug == true) + OutputLine("Compiling with comptime debugging..."); + else + OutputLine("Compiling..."); Compile(.Normal, null); } } @@ -4447,6 +4451,24 @@ namespace IDE } } + [IDECommand] + public void DebugComptime() + { + if (mDebugger.mIsRunning) + return; + + if (IsCompiling) + return; + + CheckDebugVisualizers(); + mTargetDidInitBreak = true; + mTargetStartWithStep = false; + mDebugger.ComptimeAttach(mBfBuildCompiler); + mDebugger.RehupBreakpoints(true); + mBfBuildCompiler.ForceRebuild(); + Compile(); + } + [IDECommand] void RunWithoutCompiling() { @@ -5622,6 +5644,7 @@ namespace IDE subMenu = root.AddMenuItem("&Build"); AddMenuItem(subMenu, "&Build Workspace", "Build Workspace", new => UpdateMenuItem_HasWorkspace); + AddMenuItem(subMenu, "&Debug Comptime", "Debug Comptime", new => UpdateMenuItem_HasWorkspace); AddMenuItem(subMenu, "&Clean", "Clean", new => UpdateMenuItem_DebugStopped_HasWorkspace); AddMenuItem(subMenu, "Clean Beef", "Clean Beef", new => UpdateMenuItem_DebugStopped_HasWorkspace); //subMenu.AddMenuItem("Compile Current File", null, new (menu) => { CompileCurrentFile(); }); @@ -7211,7 +7234,7 @@ namespace IDE // No 'wrong hash' warnings } else if (((hash != .None) && (sourceViewPanel.mEditData != null) && (!sourceViewPanel.mEditData.CheckHash(hash))) || - (sourceViewPanel.mHasChangedSinceLastCompile)) + (sourceViewPanel.mHasChangedSinceLastCompile) && (mDebugger?.mIsComptimeDebug != true)) { sourceViewPanel.ShowWrongHash(); } @@ -7695,6 +7718,11 @@ namespace IDE void SysKeyDown(KeyDownEvent evt) { + if (evt.mKeyCode != .Alt) + { + NOP!(); + } + if (evt.mHandled) return; @@ -8723,6 +8751,9 @@ namespace IDE if ((mVerbosity >= .Detailed) && (buildCompletedCmd.mStopwatch != null)) OutputLine("Total build time: {0:0.00}s", buildCompletedCmd.mStopwatch.ElapsedMilliseconds / 1000.0f); + if (mDebugger?.mIsComptimeDebug == true) + DebuggerComptimeStop(); + CompileDone(!buildCompletedCmd.mFailed); if (mTestManager != null) @@ -9427,6 +9458,9 @@ namespace IDE bool needsComptime = bfCompiler.GetLastHadComptimeRebuilds(); + if (mDebugger?.mIsComptimeDebug == true) + needsComptime = true; + if ((!workspaceOptions.mIncrementalBuild) && (!lastCompileHadMessages)) { tryQueueFiles = false; @@ -10376,6 +10410,9 @@ namespace IDE { Beep(MessageBeepType.Error); } + + if (mDebugger?.mIsComptimeDebug == true) + DebuggerComptimeStop(); } void DbgCopyChangedFiles(DateTime cmpTime, StringView srcDir, StringView destDir) @@ -10767,6 +10804,9 @@ namespace IDE if (mDebugger.mIsRunning) { + if (mDebugger.mIsComptimeDebug) + CancelBuild(); + mDebugger.StopDebugging(); } } @@ -12104,6 +12144,12 @@ namespace IDE return .Normal; } + void DebuggerComptimeStop() + { + mDebugger.DisposeNativeBreakpoints(); + mDebugger.Detach(); + } + void DebuggerPaused() { mDebugger.mActiveCallStackIdx = 0; @@ -14027,6 +14073,7 @@ namespace IDE [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] public static extern bool MessageBeep(MessageBeepType type); #endif + } static diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index 5f21e60c..3a4e0a0b 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -787,6 +787,7 @@ namespace IDE Add("Comment Block", "Ctrl+K, Ctrl+C"); Add("Comment Lines", "Ctrl+K, Ctrl+/"); Add("Comment Toggle", "Ctrl+K, Ctrl+T"); + Add("Debug Comptime", "Alt+F7"); Add("Duplicate Line", "Ctrl+D"); Add("Find Class", "Alt+Shift+L"); Add("Find in Document", "Ctrl+F"); diff --git a/IDE/src/ui/DisassemblyPanel.bf b/IDE/src/ui/DisassemblyPanel.bf index 2997d052..cd3802cd 100644 --- a/IDE/src/ui/DisassemblyPanel.bf +++ b/IDE/src/ui/DisassemblyPanel.bf @@ -539,6 +539,7 @@ namespace IDE.ui String sourceLineText = scope .(1024); int32 maxLine = 0; + int addrOffset = 0; for (var lineStrView in codeData.Split('\n')) { @@ -557,6 +558,9 @@ namespace IDE.ui switch (line[0]) { + case 'A': + addrOffset = (int)int64.Parse(StringView(line, 2), System.Globalization.NumberStyles.HexNumber); + continue; case 'O': isOptimized = true; addLineData = false; @@ -612,7 +616,7 @@ namespace IDE.ui //int ptrSize = 8; var addrString = scope String(disasmLine, 0, parenPos); addrString.Replace("'", ""); - lineData.mAddr = (int)int64.Parse(addrString, System.Globalization.NumberStyles.HexNumber); + lineData.mAddr = (int)int64.Parse(addrString, System.Globalization.NumberStyles.HexNumber) + addrOffset; lineData.mAddrEnd = lineData.mAddr + 1; if (prevDisasmLineData != -1) @@ -709,7 +713,7 @@ namespace IDE.ui addLineData = false; JumpEntry jumpEntry = new JumpEntry(); int64 addrFrom = (int64)mLineDatas[mLineDatas.Count - 1].mAddr; - int64 addrTo = int64.Parse(scope String(line, 2), System.Globalization.NumberStyles.HexNumber); + int64 addrTo = int64.Parse(scope String(line, 2), System.Globalization.NumberStyles.HexNumber) + addrOffset; jumpEntry.mAddrMin = (int)Math.Min(addrFrom, addrTo); jumpEntry.mAddrMax = (int)Math.Max(addrFrom, addrTo); jumpEntry.mIsReverse = jumpEntry.mAddrMin == (int)addrTo; @@ -1193,6 +1197,7 @@ namespace IDE.ui int leftIdx = -1; int rightIdx = -1; + int commaIdx = -1; String debugExpr = null; if ((cursorPos < content.mData.mTextLength) && (!((char8)content.mData.mText[cursorPos].mChar).IsWhiteSpace)) @@ -1208,59 +1213,94 @@ namespace IDE.ui content.ExtractString(lineStart, lineEnd - lineStart, lineStr); int strIdx = 0; - int colonPos = -1; - int instrStartIdx = -1; - int instrEndIdx = -1; - int firstParamIdx = -1; - int commaIdx = -1; + bool isComptime = false; + for (int i in 0..= 0) && (cursorStrIdx < lineStr.Length)) + { + leftIdx = cursorStrIdx; + rightIdx = cursorStrIdx; - int cursorStrIdx = cursorPos - lineStart; - if (cursorStrIdx > commaIdx) - { - if (commaIdx != -1) - leftIdx = lineStart + commaIdx + 1; - else - leftIdx = lineStart + firstParamIdx; - rightIdx = lineEnd - 1; - } - else if (cursorStrIdx >= firstParamIdx) - { - leftIdx = lineStart + firstParamIdx; - if (commaIdx != -1) - rightIdx = lineStart + commaIdx - 1; - else - rightIdx = lineEnd - 1; - } + while (leftIdx > 0) + { + if (lineStr[leftIdx - 1].IsWhiteSpace) + break; + leftIdx--; + } + + while (rightIdx < lineStr.Length - 1) + { + if (lineStr[rightIdx + 1].IsWhiteSpace) + break; + rightIdx++; + } + + leftIdx += lineStart; + rightIdx += lineStart; + } + } + else + { + int colonPos = -1; + int instrStartIdx = -1; + int instrEndIdx = -1; + int firstParamIdx = -1; + + for (; strIdx < lineStr.Length; strIdx++) + { + char8 c = lineStr[strIdx]; + if (colonPos == -1) + { + if (c == ':') + colonPos = strIdx; + } + else if (instrStartIdx == -1) + { + if (c.IsLower) + instrStartIdx = strIdx; + } + else if (instrEndIdx == -1) + { + if (c.IsWhiteSpace) + instrEndIdx = strIdx; + } + else if (firstParamIdx == -1) + { + if (!c.IsWhiteSpace) + firstParamIdx = strIdx; + } + else if (commaIdx == -1) + { + if (c == ',') + commaIdx = strIdx; + } + } + + int cursorStrIdx = cursorPos - lineStart; + if (cursorStrIdx > commaIdx) + { + if (commaIdx != -1) + leftIdx = lineStart + commaIdx + 1; + else + leftIdx = lineStart + firstParamIdx; + rightIdx = lineEnd - 1; + } + else if (cursorStrIdx >= firstParamIdx) + { + leftIdx = lineStart + firstParamIdx; + if (commaIdx != -1) + rightIdx = lineStart + commaIdx - 1; + else + rightIdx = lineEnd - 1; + } + } if (leftIdx != -1) { @@ -1273,6 +1313,11 @@ namespace IDE.ui int32 semiPos = (int32)debugExpr.IndexOf(';'); if (semiPos != -1) debugExpr.RemoveToEnd(semiPos); + debugExpr.Trim(); + + int atPos = debugExpr.IndexOf('@'); + if (atPos != -1) + debugExpr.RemoveToEnd(atPos); debugExpr.Replace('[', '('); debugExpr.Replace(']', ')'); @@ -1282,6 +1327,13 @@ namespace IDE.ui debugExpr.Replace("word ptr", "(int16*)"); debugExpr.Replace("byte ptr", "(int8*)"); + if ((debugExpr.Contains('(')) && (debugExpr[0].IsLetter)) + { + int parenPos = debugExpr.IndexOf('('); + debugExpr.Insert(parenPos, "*)"); + debugExpr.Insert(0, "*("); + } + if (line < mLineDatas.Count - 1) { if (mLineDatas[line].mAddrEnd != (int)0) diff --git a/IDE/src/ui/StatusBar.bf b/IDE/src/ui/StatusBar.bf index ecb0e951..24a19284 100644 --- a/IDE/src/ui/StatusBar.bf +++ b/IDE/src/ui/StatusBar.bf @@ -321,6 +321,11 @@ namespace IDE.ui float statusLabelPos = (int)GS!(-1.3f); + if ((gApp.mDebugger?.mIsComptimeDebug == true) && (gApp.mDebugger.IsPaused())) + { + completionPct = null; + } + //completionPct = 0.4f; if (completionPct.HasValue) { @@ -331,6 +336,10 @@ namespace IDE.ui using (g.PushColor(0xFF00FF00)) g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth * completionPct.Value, completionRect.mHeight); } + else if ((gApp.mDebugger?.mIsComptimeDebug == true) && (gApp.mDebugger.IsPaused())) + { + g.DrawString("Debugging Comptime", GS!(200), statusLabelPos, FontAlign.Centered, GS!(120)); + } else if ((gApp.mDebugger.mIsRunning) && (gApp.HaveSourcesChanged())) { Rect completionRect = Rect(GS!(200), GS!(1), GS!(120), GS!(17)); diff --git a/IDEHelper/Backend/BeCOFFObject.cpp b/IDEHelper/Backend/BeCOFFObject.cpp index 8a86abcf..7b8da43d 100644 --- a/IDEHelper/Backend/BeCOFFObject.cpp +++ b/IDEHelper/Backend/BeCOFFObject.cpp @@ -475,9 +475,9 @@ void BeCOFFObject::DbgMakeFuncType(BeDbgFunction* dbgFunc) if (hasThis) { if ((dbgFunc->mVariables.size() > 0) && (dbgFunc->mVariables[0] == NULL)) - outT.Write(DbgGetTypeId(dbgFunc->GetParamType(1))); // 0 is sret, 1 = this + outT.Write(DbgGetTypeId(BeValueDynCast(dbgFunc->GetParamType(1)))); // 0 is sret, 1 = this else - outT.Write(DbgGetTypeId(dbgFunc->GetParamType(0))); // 0 = this + outT.Write(DbgGetTypeId(BeValueDynCast(dbgFunc->GetParamType(0)))); // 0 = this } else outT.Write((int32)T_VOID); @@ -941,7 +941,7 @@ int BeCOFFObject::DbgGetTypeId(BeDbgType* dbgType, bool doDefine) { CV_modifier_t attr = { 0 }; attr.MOD_const = 1; - int32 elementId = DbgGetTypeId(constType->mElement); + int32 elementId = DbgGetTypeId(BeValueDynCast(constType->mElement)); DbgTStartTag(); outT.Write((int16)LF_MODIFIER); @@ -985,10 +985,10 @@ void BeCOFFObject::DbgGenerateTypeInfo() auto& outT = mDebugTSect.mData; outT.Write((int)CV_SIGNATURE_C13); - for (auto dbgType : mBeModule->mDbgModule->mTypes) + for (auto mdNode : mBeModule->mDbgModule->mTypes) { bool defineType = true; - if (auto dbgStructType = BeValueDynCast(dbgType)) + if (auto dbgStructType = BeValueDynCast(mdNode)) { if (!dbgStructType->mIsFullyDefined) defineType = false; @@ -996,7 +996,8 @@ void BeCOFFObject::DbgGenerateTypeInfo() if (defineType) { - DbgGetTypeId(dbgType, true); + if (auto dbgType = BeValueDynCast(mdNode)) + DbgGetTypeId(dbgType, true); } } @@ -1032,6 +1033,8 @@ void BeCOFFObject::DbgStartVarDefRange(BeDbgFunction* dbgFunc, BeDbgVariable* db auto funcSym = GetSymbol(dbgFunc->mValue); + auto varType = BeValueDynCast(dbgVar->mType); + auto& outS = mDebugSSect.mData; if (varLoc.mKind == BeDbgVariableLoc::Kind_SymbolAddr) { @@ -1042,14 +1045,14 @@ void BeCOFFObject::DbgStartVarDefRange(BeDbgFunction* dbgFunc, BeDbgVariable* db if (varLoc.mOfs == 0) { outS.Write((int16)S_DEFRANGE_REGISTER); - outS.Write((int16)GetCVRegNum(varLoc.mReg, dbgVar->mType->mSize * 8)); + outS.Write((int16)GetCVRegNum(varLoc.mReg, varType->mSize * 8)); CV_RANGEATTR rangeAttr = { 0 }; outS.Write(*(int16*)&rangeAttr); // offset to register } else { outS.Write((int16)S_DEFRANGE_REGISTER_REL); - outS.Write((int16)GetCVRegNum(varLoc.mReg, dbgVar->mType->mSize * 8)); + outS.Write((int16)GetCVRegNum(varLoc.mReg, varType->mSize * 8)); outS.Write((int16)0); outS.Write((int32)varLoc.mOfs); // CV_RANGEATTR rangeAttr = { 0 }; @@ -1135,6 +1138,8 @@ void BeCOFFObject::DbgSEndTag() void BeCOFFObject::DbgOutputLocalVar(BeDbgFunction* dbgFunc, BeDbgVariable* dbgVar) { + auto varType = BeValueDynCast(dbgVar->mType); + // CodeView only allows 16-bit lengths, so we need to split ranges for very long spans if (dbgVar->mDeclEnd - dbgVar->mDeclStart > 0xFFFF) { @@ -1215,7 +1220,7 @@ void BeCOFFObject::DbgOutputLocalVar(BeDbgFunction* dbgFunc, BeDbgVariable* dbgV DbgSStartTag(); outS.Write((int16)S_LOCAL); - outS.Write(DbgGetTypeId(dbgVar->mType)); + outS.Write(DbgGetTypeId(varType)); CV_LVARFLAGS flags = { 0 }; if (dbgVar->mParamNum != -1) @@ -1732,7 +1737,7 @@ void BeCOFFObject::DbgGenerateModuleInfo() else outS.Write(dbgGlobalVar->mIsLocalToUnit ? (int16)S_LDATA32 : (int16)S_GDATA32); - outS.Write(DbgGetTypeId(dbgGlobalVar->mType)); + outS.Write(DbgGetTypeId(BeValueDynCast(dbgGlobalVar->mType))); BF_ASSERT(dbgGlobalVar->mValue != NULL); @@ -1896,7 +1901,7 @@ void BeCOFFObject::WriteConst(BeCOFFSection& sect, BeConstant* constVal) { WriteConst(sect, constCast->mTarget); } - else if (auto constGep = BeValueDynCast(constVal)) + else if (auto constGep = BeValueDynCast(constVal)) { if (auto globalVar = BeValueDynCast(constGep->mTarget)) { diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index 9046a5f5..94faf3a3 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -5,6 +5,9 @@ #include "BeefySysLib/util/AllocDebug.h" #include "BeefySysLib/util/Hash.h" +#include "BeModule.h" +#include "BeContext.h" +#include "..\Compiler\CeMachine.h" #ifdef _DEBUG #define BE_EXTRA_CHECKS @@ -228,7 +231,7 @@ BeIRCodeGen::BeIRCodeGen() mBeContext = NULL; mBeModule = NULL; mHasDebugLoc = false; - mDebugging = false; + mDebugging = false; mCmdCount = 0; } @@ -736,6 +739,20 @@ void BeIRCodeGen::Read(BeValue*& beValue) BE_MEM_END("ParamType_Const_BitCast"); return; } + else if (constType == BfConstType_GEP32_1) + { + CMD_PARAM(BeConstant*, target); + CMD_PARAM(int, idx0); + + BF_ASSERT(target->GetType()->IsPointer()); + auto gepConstant = mBeModule->mAlloc.Alloc(); + gepConstant->mTarget = target; + gepConstant->mIdx0 = idx0; + + beValue = gepConstant; + BE_MEM_END("ParamType_Const_GEP32_1"); + return; + } else if (constType == BfConstType_GEP32_2) { CMD_PARAM(BeConstant*, target); @@ -743,7 +760,7 @@ void BeIRCodeGen::Read(BeValue*& beValue) CMD_PARAM(int, idx1); BF_ASSERT(target->GetType()->IsPointer()); - auto gepConstant = mBeModule->mAlloc.Alloc(); + auto gepConstant = mBeModule->mAlloc.Alloc(); gepConstant->mTarget = target; gepConstant->mIdx0 = idx0; gepConstant->mIdx1 = idx1; @@ -2852,7 +2869,15 @@ void BeIRCodeGen::HandleNextCmd() case BfIRCmd_DbgGetType: { CMD_PARAM(int, typeId); - SetResult(curId, GetTypeEntry(typeId).mDIType); + + if (mBeModule->mCeMachine != NULL) + { + auto dbgType = mBeModule->mDbgModule->mTypes.Alloc(); + dbgType->mTypeId = typeId; + SetResult(curId, dbgType); + } + else + SetResult(curId, GetTypeEntry(typeId).mDIType); } break; case BfIRCmd_DbgGetTypeInst: @@ -2974,7 +2999,21 @@ void BeIRCodeGen::HandleNextCmd() { CMD_PARAM(BeMDNode*, elementTypeNode); - BeDbgType* elementType = (BeDbgType*)elementTypeNode; + BeDbgType* elementType = BeValueDynCast(elementTypeNode); + if (elementType == NULL) + { + if (auto dbgTypeId = BeValueDynCast(elementTypeNode)) + { + auto bfElementType = mBeModule->mCeMachine->mCeModule->mContext->mTypes[dbgTypeId->mTypeId]; + auto bfPtrType = mBeModule->mCeMachine->mCeModule->CreatePointerType(bfElementType); + + auto dbgType = mBeModule->mDbgModule->mTypes.Alloc(); + dbgType->mTypeId = bfPtrType->mTypeId; + SetResult(curId, dbgType); + break; + } + } + BeDbgType* useType = elementType->FindDerivedType(BeDbgPointerType::TypeId); if (useType == NULL) { @@ -2992,7 +3031,23 @@ void BeIRCodeGen::HandleNextCmd() case BfIRCmd_DbgCreateReferenceType: { CMD_PARAM(BeMDNode*, elementTypeNode); - auto useType = mBeModule->mDbgModule->CreateReferenceType((BeDbgType*)elementTypeNode); + + BeDbgType* elementType = BeValueDynCast(elementTypeNode); + if (elementType == NULL) + { + if (auto dbgTypeId = BeValueDynCast(elementTypeNode)) + { + auto bfElementType = mBeModule->mCeMachine->mCeModule->mContext->mTypes[dbgTypeId->mTypeId]; + auto bfPtrType = mBeModule->mCeMachine->mCeModule->CreateRefType(bfElementType); + + auto dbgType = mBeModule->mDbgModule->mTypes.Alloc(); + dbgType->mTypeId = bfPtrType->mTypeId; + SetResult(curId, dbgType); + break; + } + } + + auto useType = mBeModule->mDbgModule->CreateReferenceType(elementType); SetResult(curId, useType); } break; @@ -3000,7 +3055,15 @@ void BeIRCodeGen::HandleNextCmd() { CMD_PARAM(BeMDNode*, elementTypeNode); - BeDbgType* elementType = (BeDbgType*)elementTypeNode; + BeDbgType* elementType = BeValueDynCast(elementTypeNode); + if (elementType == NULL) + { + auto dbgType = mBeModule->mDbgModule->mTypes.Alloc(); + dbgType->mElement = elementTypeNode; + SetResult(curId, dbgType); + break; + } + BeDbgType* useType = elementType->FindDerivedType(BeDbgConstType::TypeId); if (useType == NULL) { @@ -3363,7 +3426,7 @@ void BeIRCodeGen::HandleNextCmd() auto dbgVar = mBeModule->mOwnedValues.Alloc(); dbgVar->mName = name; - dbgVar->mType = (BeDbgType*)type; + dbgVar->mType = type; dbgVar->mParamNum = argNo - 1; int argIdx = argNo - 1; @@ -3411,7 +3474,7 @@ void BeIRCodeGen::HandleNextCmd() auto dbgVar = mBeModule->mOwnedValues.Alloc(); dbgVar->mName = name; - dbgVar->mType = (BeDbgType*)type; + dbgVar->mType = type; dbgVar->mScope = scope; dbgVar->mInitType = (BfIRInitType)initType; mActiveFunction->mDbgFunction->mVariables.push_back(dbgVar); @@ -3490,7 +3553,7 @@ void BeIRCodeGen::HandleNextCmd() dbgGlobalVariable->mLinkageName = linkageName; dbgGlobalVariable->mFile = (BeDbgFile*)file; dbgGlobalVariable->mLineNum = lineNum; - dbgGlobalVariable->mType = (BeDbgType*)type; + dbgGlobalVariable->mType = type; dbgGlobalVariable->mIsLocalToUnit = isLocalToUnit; dbgGlobalVariable->mValue = val; dbgGlobalVariable->mDecl = decl; diff --git a/IDEHelper/Backend/BeIRCodeGen.h b/IDEHelper/Backend/BeIRCodeGen.h index e289a78d..e18426ba 100644 --- a/IDEHelper/Backend/BeIRCodeGen.h +++ b/IDEHelper/Backend/BeIRCodeGen.h @@ -82,7 +82,7 @@ public: BeContext* mBeContext; BeModule* mBeModule; Array mSavedDebugLocs; - bool mHasDebugLoc; + bool mHasDebugLoc; int mCmdCount; Dictionary mResults; diff --git a/IDEHelper/Backend/BeMCContext.cpp b/IDEHelper/Backend/BeMCContext.cpp index a37e50dc..d51352eb 100644 --- a/IDEHelper/Backend/BeMCContext.cpp +++ b/IDEHelper/Backend/BeMCContext.cpp @@ -2279,9 +2279,34 @@ BeMCOperand BeMCContext::GetOperand(BeValue* value, bool allowMetaResult, bool a return mcOperand; } - case BeGEPConstant::TypeId: + case BeGEP1Constant::TypeId: { - auto gepConstant = (BeGEPConstant*)value; + auto gepConstant = (BeGEP1Constant*)value; + + auto mcVal = GetOperand(gepConstant->mTarget); + + BePointerType* ptrType = (BePointerType*)GetType(mcVal); + BEMC_ASSERT(ptrType->mTypeCode == BeTypeCode_Pointer); + + auto result = mcVal; + + // We assume we never do both an idx0 and idx1 at once. Fix if we change that. + int byteOffset = 0; + BeType* elementType = ptrType->mElementType; + byteOffset += gepConstant->mIdx0 * ptrType->mElementType->GetStride(); + + result = AllocRelativeVirtualReg(ptrType, result, GetImmediate(byteOffset), 1); + // The def is primary to create a single 'master location' for the GEP vreg to become legalized before use + auto vregInfo = GetVRegInfo(result); + vregInfo->mDefOnFirstUse = true; + result.mKind = BeMCOperandKind_VReg; + + return result; + } + break; + case BeGEP2Constant::TypeId: + { + auto gepConstant = (BeGEP2Constant*)value; auto mcVal = GetOperand(gepConstant->mTarget); @@ -2887,10 +2912,14 @@ static bool NeedsDecompose(BeConstant* constant) if (auto targetConstant = BeValueDynCast(castConst->mValue)) return NeedsDecompose(targetConstant); } - else if (auto castConst = BeValueDynCast(constant)) + else if (auto castConst = BeValueDynCast(constant)) { return NeedsDecompose(castConst->mTarget); } + else if (auto castConst = BeValueDynCast(constant)) + { + return NeedsDecompose(castConst->mTarget); + } return false; } @@ -8681,7 +8710,7 @@ void BeMCContext::DoActualization() else { inst->mArg0.mKind = BeMCOperandKind_VRegAddr; - vregInfo->mDbgVariable->mType = mModule->mDbgModule->CreateReferenceType(vregInfo->mDbgVariable->mType); + vregInfo->mDbgVariable->mType = mModule->mDbgModule->CreateReferenceType(BeValueDynCast(vregInfo->mDbgVariable->mType)); } } vregInfo->mWantsExprActualize = false; diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index fe1464c3..944a0546 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -497,7 +497,13 @@ void BeStructConstant::GetData(BeConstData& data) val->GetData(data); } -BeType* BeGEPConstant::GetType() +BeType* BeGEP1Constant::GetType() +{ + BePointerType* ptrType = (BePointerType*)mTarget->GetType(); + return ptrType; +} + +BeType* BeGEP2Constant::GetType() { BePointerType* ptrType = (BePointerType*)mTarget->GetType(); BF_ASSERT(ptrType->mTypeCode == BeTypeCode_Pointer); @@ -1040,6 +1046,12 @@ void BeDumpContext::ToString(StringImpl& str, BeValue* value, bool showType, boo return; } + if (auto dbgType = BeValueDynCast(mdNode)) + { + str += StrFormat("DbgTypeId: %d", dbgType->mTypeId); + return; + } + if (auto dbgVar = BeValueDynCast(mdNode)) { ToString(str, dbgVar->mType); @@ -1281,9 +1293,17 @@ void BeDumpContext::ToString(StringImpl& str, BeValue* value, bool showType, boo return; } - if (auto constantGEP = BeValueDynCast(value)) + if (auto constantGEP = BeValueDynCast(value)) + { + str += "ConstGEP1 "; + ToString(str, constantGEP->mTarget); + str += StrFormat(" %d %d", constantGEP->mIdx0); + return; + } + + if (auto constantGEP = BeValueDynCast(value)) { - str += "ConstGep "; + str += "ConstGEP2 "; ToString(str, constantGEP->mTarget); str += StrFormat(" %d %d", constantGEP->mIdx0, constantGEP->mIdx1); return; @@ -1373,7 +1393,16 @@ void BeDumpContext::ToString(StringImpl& str, BeValue* value, bool showType, boo return; } - if (auto constant = BeValueDynCast(value)) + if (auto constant = BeValueDynCast(value)) + { + ToString(str, constant->GetType()); + str += " gep ("; + ToString(str, constant->mTarget); + str += StrFormat(", %d)", constant->mIdx0); + return; + } + + if (auto constant = BeValueDynCast(value)) { ToString(str, constant->GetType()); str += " gep ("; @@ -1762,6 +1791,7 @@ BeModule::BeModule(const StringImpl& moduleName, BeContext* context) mLastDbgLoc = NULL; mActiveFunction = NULL; mDbgModule = NULL; + mCeMachine = NULL; mPrevDbgLocInline = NULL; mCurDbgLocIdx = 0; mCurLexBlockId = 0; diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index b76f3e3c..b5925b82 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -55,6 +55,7 @@ class BePhiInst; class BeSwitchInst; class BeRetInst; class BeCallInst; +class CeMachine; class BeDbgVariable; class BeDbgDeclareInst; @@ -357,10 +358,26 @@ public: } }; -class BeGEPConstant : public BeConstant +class BeGEP1Constant : public BeConstant { public: - BE_VALUE_TYPE(BeGEPConstant, BeConstant); + BE_VALUE_TYPE(BeGEP1Constant, BeConstant); + int mIdx0; + + virtual BeType* GetType(); + + virtual void HashContent(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + mTarget->HashReference(hashCtx); + hashCtx.Mixin(mIdx0); + } +}; + +class BeGEP2Constant : public BeConstant +{ +public: + BE_VALUE_TYPE(BeGEP2Constant, BeConstant); int mIdx0; int mIdx1; @@ -1646,6 +1663,26 @@ public: } }; +class BeDbgTypeId : public BeMDNode +{ +public: + BE_VALUE_TYPE(BeDbgTypeId, BeMDNode); + +public: + int mTypeId; + + BeDbgTypeId() + { + mTypeId = -1; + } + + virtual void HashContent(BeHashContext& hashCtx) override + { + hashCtx.Mixin(TypeId); + hashCtx.Mixin(mTypeId); + } +}; + class BeDbgType : public BeMDNode { public: @@ -1743,7 +1780,7 @@ public: BE_VALUE_TYPE(BeDbgConstType, BeDbgType); public: - BeDbgType* mElement; + BeMDNode* mElement; virtual void HashContent(BeHashContext& hashCtx) override { @@ -1920,7 +1957,7 @@ public: public: String mName; - BeDbgType* mType; + BeMDNode* mType; BeValue* mValue; int mParamNum; BfIRInitType mInitType; @@ -2044,7 +2081,7 @@ public: mCvArgListId = -1; } - BeDbgType* GetParamType(int paramIdx) + BeMDNode* GetParamType(int paramIdx) { /*if (!mParams.empty()) return mParams[paramIdx]->mType;*/ @@ -2209,7 +2246,7 @@ public: String mLinkageName; BeDbgFile* mFile; int mLineNum; - BeDbgType* mType; + BeMDNode* mType; bool mIsLocalToUnit; BeConstant* mValue; BeMDNode* mDecl; @@ -2246,7 +2283,7 @@ public: OwnedVector mNamespaces; OwnedVector mGlobalVariables; - OwnedVector mTypes; + OwnedVector mTypes; Array mFuncs; // Does not include methods in structs virtual void HashContent(BeHashContext& hashCtx) override; @@ -2284,6 +2321,7 @@ public: int mCurLexBlockId; BeDbgModule* mDbgModule; + CeMachine* mCeMachine; public: void AddInst(BeInst* inst); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 0984bbd3..35cc1d93 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -750,6 +750,11 @@ public: return (mKind == BfTypedValueKind_UntypedValue); } + bool IsNoValueType() const + { + return (mKind == BfTypedValueKind_NoValue); + } + bool IsParams() { return (mKind == BfTypedValueKind_ParamsSplat) || (mKind == BfTypedValueKind_Params); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index f1f0d11e..2ba99577 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -7658,6 +7658,12 @@ void BfCompiler::Cancel() mCanceling = true; mFastFinish = true; mHadCancel = true; + if (mCEMachine != NULL) + { + AutoCrit autoCrit(mCEMachine->mCritSect); + mCEMachine->mSpecialCheck = true; + mFastFinish = true; + } BfLogSysM("BfCompiler::Cancel\n"); BpEvent("BfCompiler::Cancel", ""); } @@ -7665,6 +7671,8 @@ void BfCompiler::Cancel() void BfCompiler::RequestFastFinish() { mFastFinish = true; + if (mCEMachine != NULL) + mCEMachine->mSpecialCheck = true; BfLogSysM("BfCompiler::RequestFastFinish\n"); BpEvent("BfCompiler::RequestFastFinish", ""); } diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 4b349add..36d1f69b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -21,6 +21,8 @@ #include "BfFixits.h" #include "CeMachine.h" #include "BfDefBuilder.h" +#include "CeMachine.h" +#include "CeDebugger.h" #pragma warning(pop) #pragma warning(disable:4996) @@ -4018,6 +4020,35 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef) BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringImpl& findName, bool ignoreInitialError, bool* hadError) { + if ((mModule->mCompiler->mCEMachine != NULL) && (mModule->mCompiler->mCEMachine->mDebugger != NULL) && (mModule->mCompiler->mCEMachine->mDebugger->mCurDbgState != NULL)) + { + auto ceDebugger = mModule->mCompiler->mCEMachine->mDebugger; + auto ceContext = ceDebugger->mCurDbgState->mCeContext; + auto activeFrame = ceDebugger->mCurDbgState->mActiveFrame; + if (activeFrame->mFunction->mDbgInfo != NULL) + { + int instIdx = activeFrame->GetInstIdx(); + for (auto& dbgVar : activeFrame->mFunction->mDbgInfo->mVariables) + { + if (dbgVar.mName == findName) + { + if (dbgVar.mValue.mKind == CeOperandKind_AllocaAddr) + { + return BfTypedValue(mModule->mBfIRBuilder->CreateConstAggCE(mModule->mBfIRBuilder->MapType(dbgVar.mType), activeFrame->mFrameAddr + dbgVar.mValue.mFrameOfs), dbgVar.mType, true); + } + } + } + } + + if (findName == "FR") + { + auto ptrType = mModule->CreatePointerType(mModule->GetPrimitiveType(BfTypeCode_UInt8)); + auto intVal = mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, activeFrame->mFrameAddr); + auto ptrVal = mModule->mBfIRBuilder->CreateIntToPtr(intVal, mModule->mBfIRBuilder->MapType(ptrType)); + return BfTypedValue(ptrVal, ptrType); + } + } + auto identifierNode = BfNodeDynCast(refNode); if (mModule->mCurMethodState != NULL) { @@ -4649,7 +4680,8 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe if (isFailurePass) { - mModule->Fail(StrFormat("'%s.%s' is inaccessible due to its protection level", mModule->TypeToString(typeInstance).c_str(), fieldDef->mName.c_str()), targetSrc); + if (mModule->GetCeDbgState() == NULL) + mModule->Fail(StrFormat("'%s.%s' is inaccessible due to its protection level", mModule->TypeToString(typeInstance).c_str(), fieldDef->mName.c_str()), targetSrc); } auto resolvePassData = mModule->mCompiler->mResolvePassData; @@ -6039,23 +6071,46 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* CeEvalFlags evalFlags = CeEvalFlags_None; if ((mBfEvalExprFlags & BfEvalExprFlags_NoCeRebuildFlags) != 0) evalFlags = (CeEvalFlags)(evalFlags | CeEvalFlags_NoRebuild); - auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); - if (constRet) + + if ((mModule->mIsComptimeModule) && (mModule->mCompiler->mCEMachine->mDebugger != NULL) && (mModule->mCompiler->mCEMachine->mDebugger->mCurDbgState != NULL)) { - auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); - BF_ASSERT(!constRet.mType->IsVar()); - return constRet; - } + auto ceDbgState = mModule->mCompiler->mCEMachine->mDebugger->mCurDbgState; + if ((ceDbgState->mDbgExpressionFlags & DwEvalExpressionFlag_AllowCalls) != 0) + { + ceDbgState->mHadSideEffects = true; - if (mModule->mCompiler->mFastFinish) - { - if ((mModule->mCurMethodInstance == NULL) || (!mModule->mCurMethodInstance->mIsAutocompleteMethod)) - { - // We didn't properly resolve this so queue for a rebuild later - mModule->DeferRebuildType(mModule->mCurTypeInstance); + SetAndRestoreValue prevDebugger(mModule->mCompiler->mCEMachine->mDebugger, NULL); + + evalFlags = (CeEvalFlags)(evalFlags | CeEvalFlags_DbgCall); + auto result = ceDbgState->mCeContext->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); + if (result) + return result; } + else + { + ceDbgState->mBlockedSideEffects = true; + } + } + else + { + auto constRet = mModule->mCompiler->mCEMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); + if (constRet) + { + auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); + BF_ASSERT(!constRet.mType->IsVar()); + return constRet; + } + + if (mModule->mCompiler->mFastFinish) + { + if ((mModule->mCurMethodInstance == NULL) || (!mModule->mCurMethodInstance->mIsAutocompleteMethod)) + { + // We didn't properly resolve this so queue for a rebuild later + mModule->DeferRebuildType(mModule->mCurTypeInstance); + } + } + doConstReturn = true; } - doConstReturn = true; } } else if (mModule->mIsComptimeModule) @@ -17499,6 +17554,51 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m } return; } + + if (auto ceDbgState = mModule->GetCeDbgState()) + { + if (targetFunctionName.StartsWith("__")) + { + auto ceDebugger = mModule->mCompiler->mCEMachine->mDebugger; + + auto _ResolveArg = [&](int argIdx, BfType* type = NULL) + { + if (argIdx >= args.mSize) + return BfTypedValue(); + return mModule->CreateValueFromExpression(args[argIdx], type); + }; + + if (targetFunctionName == "__getHighBits") + { + auto typedVal = _ResolveArg(0); + if ((typedVal) && (typedVal.mType->IsPrimitiveType())) + { + auto primType = (BfPrimitiveType*)typedVal.mType; + + int64 val = ceDebugger->ValueToInt(typedVal); + int64 bitCount = ceDebugger->ValueToInt(_ResolveArg(1)); + int64 resultVal = val >> (typedVal.mType->mSize * 8 - bitCount); + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, (uint64)resultVal), typedVal.mType); + return; + } + } + else if (targetFunctionName == "__clearHighBits") + { + auto typedVal = _ResolveArg(0); + if ((typedVal) && (typedVal.mType->IsPrimitiveType())) + { + auto primType = (BfPrimitiveType*)typedVal.mType; + + int64 val = ceDebugger->ValueToInt(typedVal); + int64 bitCount = ceDebugger->ValueToInt(_ResolveArg(1)); + int64 andBits = (0x8000000000000000LL) >> ((typedVal.mType->mSize - 8) * 8 + bitCount - 1); + int64 resultVal = val & ~andBits; + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, (uint64)resultVal), typedVal.mType); + return; + } + } + } + } } else if (auto expr = BfNodeDynCast(target)) { @@ -18968,7 +19068,7 @@ BfTypedValue BfExprEvaluator::PerformAssignment_CheckOp(BfAssignmentExpression* } void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue) -{ +{ auto binaryOp = BfAssignOpToBinaryOp(assignExpr->mOp); BfExpression* targetNode = assignExpr->mLeft; @@ -19375,10 +19475,54 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool } else if (!alreadyWritten) { - //ptr = mModule->LoadValue(ptr); - BF_ASSERT(ptr.IsAddr()); - convVal = mModule->LoadValue(convVal); - auto storeInst = mModule->mBfIRBuilder->CreateAlignedStore(convVal.mValue, ptr.mValue, ptr.mType->mAlign, mIsVolatileReference); + if ((mModule->mIsComptimeModule) && (mModule->mCompiler->mCEMachine->mDebugger != NULL) && (mModule->mCompiler->mCEMachine->mDebugger->mCurDbgState != NULL)) + { + auto ceDbgState = mModule->mCompiler->mCEMachine->mDebugger->mCurDbgState; + bool success = false; + + if ((convVal.mValue.IsConst()) && (ptr.mValue.IsConst())) + { + auto constant = mModule->mBfIRBuilder->GetConstant(ptr.mValue); + auto valConstant = mModule->mBfIRBuilder->GetConstant(convVal.mValue); + + auto ceTypedVal = mModule->mCompiler->mCEMachine->mDebugger->GetAddr(constant); + if (!ceTypedVal) + { + mModule->Fail("Invalid assignment address", assignExpr); + return; + } + + auto ceContext = mModule->mCompiler->mCEMachine->mCurContext; + if (ceContext->CheckMemory(ceTypedVal.mAddr, convVal.mType->mSize)) + { + if ((ceDbgState->mDbgExpressionFlags & DwEvalExpressionFlag_AllowSideEffects) != 0) + { + ceDbgState->mHadSideEffects = true; + if (ceContext->WriteConstant(mModule, ceTypedVal.mAddr, valConstant, convVal.mType)) + success = true; + } + else + { + ceDbgState->mBlockedSideEffects = true; + success = true; + } + } + } + + if (!success) + { + mModule->Fail("Assignment failed", assignExpr); + return; + } + } + + if (!alreadyWritten) + { + //ptr = mModule->LoadValue(ptr); + BF_ASSERT(ptr.IsAddr()); + convVal = mModule->LoadValue(convVal); + auto storeInst = mModule->mBfIRBuilder->CreateAlignedStore(convVal.mValue, ptr.mValue, ptr.mType->mAlign, mIsVolatileReference); + } } } } @@ -21570,7 +21714,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp leftValue.mType = leftValue.mType->GetUnderlyingType(); if ((binaryOp == BfBinaryOp_ConditionalAnd) || (binaryOp == BfBinaryOp_ConditionalOr)) - { + { if (mModule->mCurMethodState->mDeferredLocalAssignData != NULL) mModule->mCurMethodState->mDeferredLocalAssignData->BreakExtendChain(); if (mModule->mCurMethodState->mCurScope->mScopeKind == BfScopeKind_StatementTarget) diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index d5d08c0c..6413c020 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -1684,6 +1684,12 @@ String BfIRBuilder::ToString(BfIRValue irValue) BfIRValue targetConst(BfIRValueFlags_Const, box->mTarget); return ToString(targetConst) + " box to " + ToString(box->mToType); } + else if (constant->mConstType == BfConstType_GEP32_1) + { + auto gepConst = (BfConstantGEP32_1*)constant; + BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget); + return ToString(targetConst) + StrFormat(" Gep32 %d", gepConst->mIdx0); + } else if (constant->mConstType == BfConstType_GEP32_2) { auto gepConst = (BfConstantGEP32_2*)constant; @@ -4616,8 +4622,30 @@ BfIRValue BfIRBuilder::CreateIntToPtr(BfIRValue val, BfIRType type) return retVal; } +BfIRValue BfIRBuilder::CreateIntToPtr(uint64 val, BfIRType type) +{ + return CreateIntToPtr(CreateConst(BfTypeCode_IntPtr, val), type); +} + BfIRValue BfIRBuilder::CreateInBoundsGEP(BfIRValue val, int idx0) { + if (val.IsConst()) + { + auto constGEP = mTempAlloc.Alloc(); + constGEP->mConstType = BfConstType_GEP32_1; + constGEP->mTarget = val.mId; + constGEP->mIdx0 = idx0; + + BfIRValue retVal; + retVal.mFlags = BfIRValueFlags_Const; + retVal.mId = mTempAlloc.GetChunkedId(constGEP); + +#ifdef CHECK_CONSTHOLDER + retVal.mHolder = this; +#endif + return retVal; + } + BfIRValue retVal = WriteCmd(BfIRCmd_InboundsGEP1_32, val, idx0); NEW_CMD_INSERTED_IRVALUE; return retVal; @@ -4650,6 +4678,39 @@ BfIRValue BfIRBuilder::CreateInBoundsGEP(BfIRValue val, int idx0, int idx1) BfIRValue BfIRBuilder::CreateInBoundsGEP(BfIRValue val, BfIRValue idx0) { + auto constant = GetConstant(val); + if (constant != NULL) + { + if (constant->mConstType == BfConstType_IntToPtr) + { + auto fromPtrToInt = (BfConstantIntToPtr*)constant; + auto fromTarget = GetConstantById(fromPtrToInt->mTarget); + if (IsInt(fromTarget->mTypeCode)) + { + if (fromPtrToInt->mToType.mKind == BfIRTypeData::TypeKind_TypeId) + { + auto type = mModule->mContext->mTypes[fromPtrToInt->mToType.mId]; + if (type->IsPointer()) + { + auto elementType = type->GetUnderlyingType(); + auto addConstant = GetConstant(idx0); + if ((addConstant != NULL) && (IsInt(addConstant->mTypeCode))) + { + return CreateIntToPtr(CreateConst(fromTarget->mTypeCode, (uint64)(fromTarget->mInt64 + addConstant->mInt64 * elementType->GetStride())), + fromPtrToInt->mToType); + } + } + } + } + } + + if (auto idxConstant = GetConstant(idx0)) + { + if (IsInt(idxConstant->mTypeCode)) + return CreateInBoundsGEP(val, idxConstant->mInt32); + } + } + BfIRValue retVal = WriteCmd(BfIRCmd_InBoundsGEP1, val, idx0); NEW_CMD_INSERTED_IRVALUE; return retVal; diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 15a7f03b..31ca43ed 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -126,6 +126,7 @@ enum BfConstType BfConstType_GlobalVar = BfTypeCode_Length, BfConstType_BitCast, BfConstType_BitCastNull, + BfConstType_GEP32_1, BfConstType_GEP32_2, BfConstType_ExtractValue, BfConstType_PtrToInt, @@ -878,6 +879,13 @@ struct BfConstantIntToPtr BfIRType mToType; }; +struct BfConstantGEP32_1 +{ + BfConstType mConstType; + int mTarget; + int mIdx0; +}; + struct BfConstantGEP32_2 { BfConstType mConstType; @@ -1223,6 +1231,7 @@ public: BfIRValue CreateBitCast(BfIRValue val, BfIRType type); BfIRValue CreatePtrToInt(BfIRValue val, BfTypeCode typeCode); BfIRValue CreateIntToPtr(BfIRValue val, BfIRType type); + BfIRValue CreateIntToPtr(uint64 val, BfIRType type); BfIRValue CreateInBoundsGEP(BfIRValue val, int idx0); BfIRValue CreateInBoundsGEP(BfIRValue val, int idx0, int idx1); BfIRValue CreateInBoundsGEP(BfIRValue val, BfIRValue idx0); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index c14c8082..5b973999 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -25,6 +25,7 @@ #include "BfDefBuilder.h" #include "BfDeferEvalChecker.h" #include "CeMachine.h" +#include "CeDebugger.h" #include #include @@ -1045,7 +1046,7 @@ void BfModule::FinishInit() mHasFullDebugInfo = moduleOptions.mEmitDebugInfo == 1; if (mIsComptimeModule) - mHasFullDebugInfo = false; + mHasFullDebugInfo = true; if (((!mCompiler->mIsResolveOnly) && (!mIsScratchModule) && (moduleOptions.mEmitDebugInfo != 0) && (mIsReified)) || (mIsComptimeModule)) @@ -1732,6 +1733,15 @@ String* BfModule::GetStringPoolString(BfIRValue constantStr, BfIRConstHolder * c return NULL; } +CeDbgState* BfModule::GetCeDbgState() +{ + if (!mIsComptimeModule) + return NULL; + if ((mCompiler->mCEMachine != NULL) && (mCompiler->mCEMachine->mDebugger != NULL)) + return mCompiler->mCEMachine->mDebugger->mCurDbgState; + return NULL; +} + BfIRValue BfModule::GetStringCharPtr(int stringId, bool force) { if ((mBfIRBuilder->mIgnoreWrites) && (!force)) @@ -3066,8 +3076,10 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers //BF_ASSERT(refNode != NULL); - if (mIsComptimeModule) + if ((mIsComptimeModule) && (!mCompiler->mCEMachine->mDbgPaused)) { + mHadBuildError = true; + if ((mCompiler->mCEMachine->mCurContext != NULL) && (mCompiler->mCEMachine->mCurContext->mCurTargetSrc != NULL)) { BfError* bfError = mCompiler->mPassInstance->Fail("Comptime method generation had errors", mCompiler->mCEMachine->mCurContext->mCurTargetSrc); @@ -3075,8 +3087,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers mCompiler->mPassInstance->MoreInfo(error, refNode); return bfError; } - - mHadBuildError = true; + return NULL; } @@ -4139,7 +4150,7 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance* } } else if (mBfIRBuilder != NULL) - { + { SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeInstance); SetAndRestoreValue prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites, true); @@ -12452,6 +12463,39 @@ BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bo return GetDefaultTypedValue(typedValue.mType); } } + + if ((mIsComptimeModule) && (mCompiler->mCEMachine->mDebugger != NULL) && (mCompiler->mCEMachine->mDebugger->mCurDbgState != NULL)) + { + auto ceDebugger = mCompiler->mCEMachine->mDebugger; + auto ceContext = ceDebugger->mCurDbgState->mCeContext; + auto activeFrame = ceDebugger->mCurDbgState->mActiveFrame; + + auto ceTypedValue = ceDebugger->GetAddr(constantValue); + if (ceTypedValue) + { + if ((typedValue.mType->IsObjectOrInterface()) || (typedValue.mType->IsPointer())) + { + void* data = ceContext->GetMemoryPtr(ceTypedValue.mAddr, sizeof(addr_ce)); + if (data == NULL) + { + Fail("Invalid address", refNode); + return GetDefaultTypedValue(typedValue.mType); + } + + addr_ce dataAddr = *(addr_ce*)data; + return BfTypedValue(mBfIRBuilder->CreateIntToPtr( + mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)dataAddr), mBfIRBuilder->MapType(typedValue.mType)), typedValue.mType); + } + + auto constVal = ceContext->CreateConstant(this, ceContext->mMemory.mVals + ceTypedValue.mAddr, typedValue.mType); + if (!constVal) + { + Fail("Failed to create const", refNode); + return GetDefaultTypedValue(typedValue.mType); + } + return BfTypedValue(constVal, typedValue.mType); + } + } } } @@ -14605,6 +14649,11 @@ void BfModule::MarkUsingThis() BfTypedValue BfModule::GetThis(bool markUsing) { + if ((mIsComptimeModule) && (mCompiler->mCEMachine->mDebugger != NULL) && (mCompiler->mCEMachine->mDebugger->mCurDbgState != NULL)) + { + return mCompiler->mCEMachine->mDebugger->mCurDbgState->mExplicitThis; + } + auto useMethodState = mCurMethodState; while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing)) { @@ -14628,7 +14677,7 @@ BfTypedValue BfModule::GetThis(bool markUsing) } } else - { + { //TODO: Do we allow useMethodState to be NULL anymore? return BfTypedValue(); } @@ -16616,6 +16665,7 @@ void BfModule::EmitDtorBody() } else { + PopulateType(fieldInst->mResolvedType); if (fieldInst->mResolvedType->IsValuelessType()) { value = mBfIRBuilder->GetFakeVal(); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index e33a097e..f7167bf3 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -33,6 +33,7 @@ class BfType; class BfResolvedType; class BfExprEvaluator; class CeEmitContext; +class CeDbgState; enum BfPopulateType { @@ -1543,6 +1544,7 @@ public: void VerifyOnDemandMethods(); bool IsSkippingExtraResolveChecks(); bool AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool& isWhileSpecializing, bool isWarning); + CeDbgState* GetCeDbgState(); BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false, bool deferError = false); BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL); BfError* FailAfter(const StringImpl& error, BfAstNode* refNode); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 84f0355b..6892aa30 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -12086,7 +12086,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if ((typedVal.mType->IsPointer()) && (toType->IsIntPtr())) { if ((!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) - { + { if (!ignoreErrors) Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); else if (!silentFail) diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 051837ae..beec3718 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -720,7 +720,7 @@ BfBlock* BfParser::ParseInlineBlock(int spaceIdx, int endIdx) while (true) { - NextToken(endIdx + 1); + NextToken(endIdx + 1, false, true); if (mSyntaxToken == BfSyntaxToken_HIT_END_IDX) { mSrcIdx = usedEndIdx; @@ -1384,7 +1384,7 @@ double BfParser::ParseLiteralDouble() return strtod(buf, NULL); } -void BfParser::NextToken(int endIdx, bool outerIsInterpolate) +void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePreprocessor) { auto prevToken = mToken; @@ -2337,7 +2337,13 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) } break; case '#': - HandlePreprocessor(); + if (disablePreprocessor) + { + TokenFail("Unexpected character"); + continue; + } + else + HandlePreprocessor(); if (mSyntaxToken == BfSyntaxToken_EOF) return; break; diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index 3c95ed8d..0a26e9f7 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -227,7 +227,7 @@ public: void MoveSource(const char* data, int length); // Takes ownership of data ptr void RefSource(const char* data, int length); void MakeNegative(uint64& val, bool& hadOverflow); - void NextToken(int endIdx = -1, bool outerIsInterpolate = false); + void NextToken(int endIdx = -1, bool outerIsInterpolate = false, bool disablePreprocessor = false); BfAstNode* CreateNode(); void Parse(BfPassInstance* passInstance); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index b1909be4..f86ea0e3 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -3503,6 +3503,10 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa BF_ASSERT(sizeExpr != NULL); if (sizeExpr != NULL) { + BfMethodState methodState; + SetAndRestoreValue prevMethodState(ctx->mModule->mCurMethodState, &methodState); + methodState.mTempKind = BfMethodState::TempKind_Static; + BfConstResolver constResolver(ctx->mModule); BfType* intType = ctx->mModule->GetPrimitiveType(BfTypeCode_IntPtr); constResolver.mAllowGenericConstValue = true; diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 363411c3..7a0e49b2 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3523,7 +3523,7 @@ void BfModule::VisitCodeBlock(BfBlock* block) mCurMethodState->mMixinState->mResultExpr = expr; break; } - else if ((mCurMethodInstance->IsMixin()) && (mCurMethodState->mCurScope == &mCurMethodState->mHeadScope)) + else if ((mCurMethodInstance != NULL) && (mCurMethodInstance->IsMixin()) && (mCurMethodState->mCurScope == &mCurMethodState->mHeadScope)) { // Only in mixin definition - result ignored CreateValueFromExpression(expr); diff --git a/IDEHelper/Compiler/BfUtil.cpp b/IDEHelper/Compiler/BfUtil.cpp index 5998105f..eab99f78 100644 --- a/IDEHelper/Compiler/BfUtil.cpp +++ b/IDEHelper/Compiler/BfUtil.cpp @@ -27,6 +27,14 @@ String Beefy::EncodeDataPtr(uint32 addr, bool doPrefix) return StrFormat("%08X", addr); } +String Beefy::EncodeDataPtr(int addr, bool doPrefix) +{ + if (doPrefix) + return StrFormat("0x%08X", addr); + else + return StrFormat("%08X", addr); +} + String Beefy::EncodeDataPtr(uint64 addr, bool doPrefix) { if (doPrefix) diff --git a/IDEHelper/Compiler/BfUtil.h b/IDEHelper/Compiler/BfUtil.h index 7232c4bf..92fb28cf 100644 --- a/IDEHelper/Compiler/BfUtil.h +++ b/IDEHelper/Compiler/BfUtil.h @@ -269,6 +269,7 @@ void* DecodeLocalDataPtr(const char*& strRef); String EncodeDataPtr(void* addr, bool doPrefix); String EncodeDataPtr(uint32 addr, bool doPrefix); String EncodeDataPtr(uint64 addr, bool doPrefix); +String EncodeDataPtr(int addr, bool doPrefix); void* ZeroedAlloc(int size); /*template T* ZeroedAlloc() diff --git a/IDEHelper/Compiler/CeDebugger.cpp b/IDEHelper/Compiler/CeDebugger.cpp new file mode 100644 index 00000000..3e63ef12 --- /dev/null +++ b/IDEHelper/Compiler/CeDebugger.cpp @@ -0,0 +1,4239 @@ +#include "CeDebugger.h" +#include "CeMachine.h" +#include "BfCompiler.h" +#include "../DebugManager.h" +#include "BeefySysLib/util/BeefPerf.h" +#include "BfParser.h" +#include "BfReducer.h" +#include "BeefySysLib/util/UTF8.h" +#include "BfUtil.h" +#include "BfExprEvaluator.h" +#include "BeefySysLib/util/BitSet.h" +#include "../DebugVisualizers.h" + +USING_NS_BF; + +static addr_ce DecodeTargetDataPtr(const char*& strRef) +{ + addr_ce val = (addr_ce)stouln(strRef, sizeof(addr_ce) * 2); + strRef += sizeof(addr_ce) * 2; + return val; +} + +////////////////////////////////////////////////////////////////////////// + +CePendingExpr::CePendingExpr() +{ + mThreadId = -1; + mCallStackIdx = -1; + mParser = NULL; + mCursorPos = -1; + mExprNode = NULL; + mIdleTicks = 0; + mExplitType = NULL; + mExpressionFlags = DwEvalExpressionFlag_None; +} + +CePendingExpr::~CePendingExpr() +{ + delete mParser; +} + +////////////////////////////////////////////////////////////////////////// + + +CeEvaluationContext::CeEvaluationContext(CeDebugger* winDebugger, const StringImpl& expr, CeFormatInfo* formatInfo, BfTypedValue contextValue) +{ + Init(winDebugger, expr, formatInfo, contextValue); +} + +void CeEvaluationContext::Init(CeDebugger* ceDebugger, const StringImpl& expr, CeFormatInfo* formatInfo, BfTypedValue contextValue) +{ + mDebugger = ceDebugger; + + mCallStackIdx = 0; + mParser = NULL; + mReducer = NULL; + mPassInstance = NULL; + mExprEvaluator = NULL; + mExprNode = NULL; + + if (expr.empty()) + return; + + int atPos = (int)expr.IndexOf('@'); + if ((atPos != -1) && (atPos < expr.mLength - 2) && (expr[atPos + 1] == '0') && (expr[atPos + 2] == 'x')) + { + bool isValid = true; + for (int i = 0; i < atPos; i++) + { + char c = expr[i]; + if ((c < '0') || (c > '9')) + { + isValid = false; + break; + } + } + + if (isValid) + { + int parseLength = expr.mLength; + for (int i = 0; i < expr.mLength; i++) + { + if ((expr[i] == ',') || (::isspace((uint8)expr[i]))) + { + parseLength = i; + break; + } + } + mExprString = expr.Substring(0, parseLength); + + String typeIdStr = expr.Substring(0, atPos); + String addrStr = expr.Substring(atPos + 3, parseLength - atPos - 3); + + int typeId = strtol(typeIdStr.c_str(), NULL, 10); + int64 addrVal = strtoll(addrStr.c_str(), NULL, 16); + + if ((typeId != 0) && (addrVal != 0)) + { + auto type = ceDebugger->mCompiler->mContext->FindTypeById(typeId); + if (type != NULL) + { + auto module = ceDebugger->mCeMachine->mCeModule; + + if (type->IsObjectOrInterface()) + { + mResultOverride = BfTypedValue(module->mBfIRBuilder->CreateIntToPtr( + module->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)addrVal), module->mBfIRBuilder->MapType(type)), type); + } + else + { + mResultOverride = BfTypedValue(module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(type), (addr_ce)addrVal), type, true); + } + } + } + return; + } + } + + mParser = new BfParser(ceDebugger->mCompiler->mSystem); + mPassInstance = new BfPassInstance(ceDebugger->mCompiler->mSystem); + auto terminatedExpr = expr + ";"; + mParser->SetSource(terminatedExpr.c_str(), (int)terminatedExpr.length()); + mParser->Parse(mPassInstance); + + mReducer = new BfReducer(); + mReducer->mAlloc = mParser->mAlloc; + mReducer->mSystem = ceDebugger->mCompiler->mSystem; + mReducer->mPassInstance = mPassInstance; + mReducer->mVisitorPos = BfReducer::BfVisitorPos(mParser->mRootNode); + mReducer->mVisitorPos.MoveNext(); + mReducer->mSource = mParser; + mExprNode = mReducer->CreateExpression(mParser->mRootNode->GetFirst()); + mParser->Close(); + mExprEvaluator = new BfExprEvaluator(ceDebugger->mCeMachine->mCeModule); + + if ((formatInfo != NULL) && (mExprNode != NULL) && (mExprNode->GetSrcEnd() < (int)expr.length())) + { + String formatFlags = expr.Substring(mExprNode->GetSrcEnd()); + String errorString = "Invalid expression"; + if (!ceDebugger->ParseFormatInfo(formatFlags, formatInfo, mPassInstance, NULL, NULL, &errorString, contextValue)) + { + mPassInstance->FailAt(errorString, mParser->mSourceData, mExprNode->GetSrcEnd(), (int)expr.length() - mExprNode->GetSrcEnd()); + formatFlags = ""; + } + } + + if (formatInfo != NULL) + { + mExplicitThis = formatInfo->mExplicitThis; + mCallStackIdx = formatInfo->mCallStackIdx; + } + + mExprNode->ToString(mExprString); +} + +bool CeEvaluationContext::HasExpression() +{ + return !mExprString.IsEmpty(); +} + +CeEvaluationContext::~CeEvaluationContext() +{ + delete mParser; + delete mReducer; + delete mExprEvaluator; + delete mPassInstance; +} + +BfTypedValue CeEvaluationContext::EvaluateInContext(BfTypedValue contextTypedValue) +{ + if (mResultOverride) + return mResultOverride; + + if (mExprNode == NULL) + return BfTypedValue(); + mPassInstance->ClearErrors(); + + auto ceFrame = mDebugger->GetFrame(mCallStackIdx); + + auto module = mDebugger->mCeMachine->mCeModule; + + SetAndRestoreValue prevTypeInstance(module->mCurTypeInstance, ceFrame->mFunction->mMethodInstance->GetOwner()); + SetAndRestoreValue prevMethodInstance(module->mCurMethodInstance, ceFrame->mFunction->mMethodInstance); + SetAndRestoreValue prevPassInstance(mDebugger->mCompiler->mPassInstance, mPassInstance); + SetAndRestoreValue prevIgnoreWrites(module->mBfIRBuilder->mIgnoreWrites, true); + + BfMethodState methodState; + SetAndRestoreValue prevMethodState(module->mCurMethodState, &methodState); + methodState.mTempKind = module->mCurMethodInstance->mMethodDef->mIsStatic ? BfMethodState::TempKind_Static : BfMethodState::TempKind_NonStatic; + + CeDbgState dbgState; + dbgState.mActiveFrame = ceFrame; + dbgState.mCeContext = mDebugger->mCeMachine->mCurContext; + if (contextTypedValue) + dbgState.mExplicitThis = contextTypedValue; + else + dbgState.mExplicitThis = mExplicitThis; + SetAndRestoreValue prevDbgState(mDebugger->mCurDbgState, &dbgState); + + BfTypedValue exprResult; + mExprEvaluator->VisitChildNoRef(mExprNode); + + auto result = mExprEvaluator->mResult; + if ((result) && (!result.mType->IsComposite())) + result = module->LoadValue(result); + + return result; +} + +bool CeEvaluationContext::HadError() +{ + return (mPassInstance != NULL) && (mPassInstance->mFailedIdx != 0); +} + +String CeEvaluationContext::GetErrorStr() +{ + if (mPassInstance == NULL) + return ""; + String errorStr = mPassInstance->mErrors[0]->mError; + if (mExprNode != NULL) + { + errorStr += ": "; + errorStr += mExprNode->ToString(); + } + return errorStr; +} + +////////////////////////////////////////////////////////////////////////// + +CeDebugger::CeDebugger(DebugManager* debugManager, BfCompiler* bfCompiler) +{ + mDebugManager = debugManager; + mCompiler = bfCompiler; + mCeMachine = bfCompiler->mCEMachine; + mRunState = RunState_Running; + mCeMachine->mDebugger = this; + mCeMachine->mDebugEvent.Reset(); + mDebugPendingExpr = NULL; + mCurDbgState = NULL; + mBreakpointVersion = 0; + mBreakpointCacheDirty = false; + mBreakpointFramesDirty = false; + mCurDisasmFuncId = 0; + mActiveBreakpoint = NULL; + mCurEvaluationContext = NULL; +} + +CeDebugger::~CeDebugger() +{ + mCeMachine->mDebugEvent.Set(true); + mCeMachine->mDebugger = NULL; + delete mDebugPendingExpr; + + for (auto breakpoint : mBreakpoints) + delete breakpoint; + + for (auto kv : mFileInfo) + delete kv.mValue; +} + +void CeDebugger::OutputMessage(const StringImpl& msg) +{ + if (this == NULL) + return; + AutoCrit autoCrit(mDebugManager->mCritSect); + mDebugManager->mOutMessages.push_back("msg " + msg); +} + +void CeDebugger::OutputRawMessage(const StringImpl& msg) +{ + if (this == NULL) + return; + AutoCrit autoCrit(mDebugManager->mCritSect); + mDebugManager->mOutMessages.push_back(msg); +} + +int CeDebugger::GetAddrSize() +{ + return sizeof(addr_ce); +} + +bool CeDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult) +{ + return false; +} + +void CeDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock, bool hotSwapEnabled) +{ +} + +bool CeDebugger::Attach(int processId, BfDbgAttachFlags attachFlags) +{ + return false; +} + +void CeDebugger::Run() +{ +} + +void CeDebugger::HotLoad(const Array& objectFiles, int hotIdx) +{ +} + +void CeDebugger::InitiateHotResolve(DbgHotResolveFlags flags) +{ +} + +intptr CeDebugger::GetDbgAllocHeapSize() +{ + return intptr(); +} + +String CeDebugger::GetDbgAllocInfo() +{ + return String(); +} + +void CeDebugger::Update() +{ + if ((mRunState == RunState_Terminated) || (mRunState == RunState_Terminating)) + return; + + AutoCrit autoCrit(mCeMachine->mCritSect); + if (mCeMachine->mDbgPaused) + { + mRunState = RunState_Paused; + } + else + { + mRunState = RunState_Running; + } +} + +void CeDebugger::UpdateBreakpointFrames() +{ + if (mBreakpointCacheDirty) + UpdateBreakpointCache(); + for (auto& callStack : mCeMachine->mCurContext->mCallStack) + { + if (callStack.mFunction->mBreakpointVersion != mBreakpointVersion) + UpdateBreakpoints(callStack.mFunction); + } +} + +void CeDebugger::ContinueDebugEvent() +{ + mRunState = RunState_Running; + mActiveBreakpoint = NULL; + + if (mBreakpointFramesDirty) + UpdateBreakpointFrames(); + + mCeMachine->mDebugEvent.Set(); +} + +void CeDebugger::ForegroundTarget() +{ +} + +Breakpoint* CeDebugger::CreateBreakpoint(const StringImpl& fileName, int lineNum, int wantColumn, int instrOffset) +{ + ClearBreakpointCache(); + + auto breakpoint = new CeBreakpoint(); + breakpoint->mFilePath = fileName; + breakpoint->mRequestedLineNum = lineNum; + breakpoint->mLineNum = lineNum; + breakpoint->mColumn = wantColumn; + breakpoint->mInstrOffset = instrOffset; + mBreakpoints.Add(breakpoint); + + mBreakpointVersion++; + + return breakpoint; +} + +Breakpoint* CeDebugger::CreateMemoryBreakpoint(intptr addr, int byteCount) +{ + return nullptr; +} + +Breakpoint* CeDebugger::CreateSymbolBreakpoint(const StringImpl& symbolName) +{ + return nullptr; +} + +Breakpoint* CeDebugger::CreateAddressBreakpoint(intptr address) +{ + return nullptr; +} + +uintptr CeDebugger::GetBreakpointAddr(Breakpoint* breakpoint) +{ + if (mBreakpointCacheDirty) + { + UpdateBreakpointCache(); + UpdateBreakpointAddrs(); + } + return breakpoint->GetAddr(); +} + +void CeDebugger::CheckBreakpoint(Breakpoint* breakpoint) +{ +} + +void CeDebugger::HotBindBreakpoint(Breakpoint* breakpoint, int lineNum, int hotIdx) +{ +} + +int64 CeDebugger::ValueToInt(const BfTypedValue& typedVal) +{ + auto constant = mCeMachine->mCeModule->mBfIRBuilder->GetConstant(typedVal.mValue); + if (constant == NULL) + return 0; + + if (typedVal.IsAddr()) + { + BfType* type = typedVal.mType; + if (type->IsTypedPrimitive()) + type = type->GetUnderlyingType(); + + if ((type->IsInteger()) || (type->IsBoolean())) + { + auto primType = (BfPrimitiveType*)type; + + auto ceTypedVal = GetAddr(constant); + if (ceTypedVal) + { + auto ceContext = mCeMachine->mCurContext; + + int64 val = 0; + memcpy(&val, ceContext->mMemory.mVals + ceTypedVal.mAddr, type->mSize); + + switch (primType->mTypeDef->mTypeCode) + { + case BfTypeCode_Int8: + val = *(int8*)&val; + break; + case BfTypeCode_Int16: + val = *(int8*)&val; + break; + case BfTypeCode_Int32: + val = *(int8*)&val; + break; + } + return val; + } + } + + return 0; + } + if ((BfIRConstHolder::IsInt(constant->mTypeCode)) || (constant->mTypeCode == BfTypeCode_Boolean)) + return constant->mInt64; + return 0; +} + +void CeDebugger::DeleteBreakpoint(Breakpoint* breakpoint) +{ + if (mActiveBreakpoint == breakpoint) + mActiveBreakpoint = NULL; + mBreakpoints.Remove((CeBreakpoint*)breakpoint); + delete breakpoint; + ClearBreakpointCache(); +} + +void CeDebugger::DetachBreakpoint(Breakpoint* breakpoint) +{ +} + +void CeDebugger::MoveBreakpoint(Breakpoint* breakpoint, int lineNum, int wantColumn, bool rebindNow) +{ + breakpoint->mLineNum = lineNum; + breakpoint->mColumn = wantColumn; + ClearBreakpointCache(); +} + +void CeDebugger::MoveMemoryBreakpoint(Breakpoint* breakpoint, intptr addr, int byteCount) +{ +} + +void CeDebugger::DisableBreakpoint(Breakpoint* breakpoint) +{ +} + +void CeDebugger::SetBreakpointCondition(Breakpoint* breakpoint, const StringImpl& condition) +{ +} + +void CeDebugger::SetBreakpointLogging(Breakpoint* breakpoint, const StringImpl& logging, bool breakAfterLogging) +{ +} + +Breakpoint* CeDebugger::FindBreakpointAt(intptr address) +{ + return nullptr; +} + +Breakpoint* CeDebugger::GetActiveBreakpoint() +{ + return mActiveBreakpoint; +} + +void CeDebugger::BreakAll() +{ + mCeMachine->mSpecialCheck = true; + mCeMachine->mDbgWantBreak = true; + +} + +bool CeDebugger::TryRunContinue() +{ + return false; +} + +bool CeDebugger::SetupStep(int frameIdx) +{ + auto ceFrame = GetFrame(frameIdx); + if (ceFrame == NULL) + { + ContinueDebugEvent(); + return false; + } + + int entryIdx = 0; + auto curEntry = ceFrame->mFunction->FindEmitEntry(ceFrame->GetInstIdx(), &entryIdx); + if (curEntry == NULL) + { + ContinueDebugEvent(); + return false; + } + + auto ceMachine = mCeMachine; + auto ceContext = mCeMachine->mCurContext; + + if (entryIdx < ceFrame->mFunction->mEmitTable.mSize - 1) + { + int checkIdx = entryIdx + 1; + while (checkIdx < ceFrame->mFunction->mEmitTable.mSize) + { + auto checkEntry = &ceFrame->mFunction->mEmitTable[checkIdx]; + ceMachine->mStepState.mNextInstIdx = checkEntry->mCodePos; + if ((checkEntry->mScope != curEntry->mScope) || (checkEntry->mLine != curEntry->mLine)) + break; + ++checkIdx; + } + } + else + ceMachine->mStepState.mNextInstIdx = ceFrame->mFunction->mCode.mSize; + ceMachine->mStepState.mStartDepth = ceContext->mCallStack.mSize - frameIdx; + ceMachine->mSpecialCheck = true; + + ContinueDebugEvent(); + return true; +} + +void CeDebugger::StepInto(bool inAssembly) +{ + if (!SetupStep()) + return; + mCeMachine->mStepState.mKind = inAssembly ? CeStepState::Kind_StepInfo_Asm : CeStepState::Kind_StepInfo; +} + +void CeDebugger::StepIntoSpecific(intptr addr) +{ +} + +void CeDebugger::StepOver(bool inAssembly) +{ + if (!SetupStep()) + return; + mCeMachine->mStepState.mKind = inAssembly ? CeStepState::Kind_StepOver_Asm : CeStepState::Kind_StepOver; +} + +void CeDebugger::StepOut(bool inAssembly) +{ + if (!SetupStep(1)) + return; + mCeMachine->mStepState.mKind = inAssembly ? CeStepState::Kind_StepOut_Asm : CeStepState::Kind_StepOut; +} + +void CeDebugger::SetNextStatement(bool inAssembly, const StringImpl& fileName, int64 lineNumOrAsmAddr, int wantColumn) +{ + auto ceFrame = GetFrame(0); + if (ceFrame == NULL) + return; + + if (inAssembly) + { + int32 instIdx = (int32)lineNumOrAsmAddr; + if (instIdx < ceFrame->mFunction->mCode.mSize) + { + mCeMachine->mSpecialCheck = true; + mCeMachine->mStepState.mKind = CeStepState::Kind_Jmp; + mCeMachine->mStepState.mNextInstIdx = instIdx; + ContinueDebugEvent(); + } + } + else + { + for (auto& emitEntry : ceFrame->mFunction->mEmitTable) + { + if (emitEntry.mScope == -1) + continue; + auto& scope = ceFrame->mFunction->mDbgScopes[emitEntry.mScope]; + if ((FileNameEquals(fileName, scope.mFilePath) && (emitEntry.mLine == lineNumOrAsmAddr))) + { + mCeMachine->mSpecialCheck = true; + mCeMachine->mStepState.mKind = CeStepState::Kind_Jmp; + mCeMachine->mStepState.mNextInstIdx = emitEntry.mCodePos; + ContinueDebugEvent(); + return; + } + } + } +} + +CeFrame* CeDebugger::GetFrame(int callStackIdx) +{ + auto ceContext = mCeMachine->mCurContext; + if (ceContext == NULL) + return NULL; + if (callStackIdx < ceContext->mCallStack.mSize) + { + int stackIdx = ceContext->mCallStack.mSize - callStackIdx - 1; + auto ceFrame = &ceContext->mCallStack[stackIdx]; + return ceFrame; + } + return NULL; +} + +String CeDebugger::EvaluateContinue(CePendingExpr* pendingExpr, BfPassInstance& bfPassInstance) +{ + auto ceFrame = GetFrame(pendingExpr->mCallStackIdx); + if (ceFrame == NULL) + { + return "!failed"; + } + + if (pendingExpr->mExprNode == NULL) + { + return "!failed"; + } + + auto module = mCeMachine->mCeModule; + + SetAndRestoreValue prevTypeInstance(module->mCurTypeInstance, ceFrame->mFunction->mMethodInstance->GetOwner()); + SetAndRestoreValue prevMethodInstance(module->mCurMethodInstance, ceFrame->mFunction->mMethodInstance); + SetAndRestoreValue prevPassInstance(mCompiler->mPassInstance, &bfPassInstance); + SetAndRestoreValue prevIgnoreWrites(module->mBfIRBuilder->mIgnoreWrites, true); + + BfMethodState methodState; + SetAndRestoreValue prevMethodState(module->mCurMethodState, &methodState); + methodState.mTempKind = module->mCurMethodInstance->mMethodDef->mIsStatic ? BfMethodState::TempKind_Static : BfMethodState::TempKind_NonStatic; + + CeDbgState dbgState; + dbgState.mActiveFrame = ceFrame; + dbgState.mCeContext = mCeMachine->mCurContext; + dbgState.mExplicitThis = pendingExpr->mFormatInfo.mExplicitThis; + dbgState.mDbgExpressionFlags = pendingExpr->mExpressionFlags; + SetAndRestoreValue prevDbgState(mCurDbgState, &dbgState); + + BfTypedValue exprResult; + + if (auto typeRef = BfNodeDynCast(pendingExpr->mExprNode)) + { + auto resultType = mCeMachine->mCeModule->ResolveTypeRef(typeRef); + if (resultType != NULL) + exprResult = BfTypedValue(resultType); + } + else + { + BfExprEvaluator exprEvaluator(mCeMachine->mCeModule); + exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_Comptime); + exprEvaluator.VisitChildNoRef(pendingExpr->mExprNode); + exprResult = exprEvaluator.mResult; + if ((exprResult) && (!exprResult.mType->IsComposite())) + exprResult = module->LoadValue(exprResult); + } + + if (dbgState.mBlockedSideEffects) + return "!sideeffects"; + + if (!exprResult) + { + auto resultType = mCeMachine->mCeModule->ResolveTypeRef(pendingExpr->mExprNode, {}, BfPopulateType_Data, BfResolveTypeRefFlag_IgnoreLookupError); + if (resultType != NULL) + { + exprResult = BfTypedValue(resultType); + bfPassInstance.ClearErrors(); + } + } + + String val; + if (bfPassInstance.HasFailed()) + { + BfLogDbgExpr("Evaluate Failed: %s\n", bfPassInstance.mErrors[0]->mError.c_str()); + val = StrFormat("!%d\t%d\t%s", bfPassInstance.mErrors[0]->GetSrcStart(), bfPassInstance.mErrors[0]->GetSrcLength(), bfPassInstance.mErrors[0]->mError.c_str()); + } + else + { + val = TypedValueToString(exprResult, pendingExpr->mExprNode->ToString(), pendingExpr->mFormatInfo, (pendingExpr->mExpressionFlags & DwEvalExpressionFlag_FullPrecision) != 0); + + if ((!val.empty()) && (val[0] == '!')) + return val; + + if (pendingExpr->mFormatInfo.mRawString) + return val; + + if (bfPassInstance.HasMessages()) + { + for (auto error : bfPassInstance.mErrors) + { + if (error->mIsWarning) + { + val += "\n:warn\t"; + val += error->mError; + } + } + } + + if (!pendingExpr->mFormatInfo.mReferenceId.empty()) + val += "\n:referenceId\t" + pendingExpr->mFormatInfo.mReferenceId; + + // if ((exprResult.mSrcAddress != 0) && (HasMemoryBreakpoint(exprResult.mSrcAddress, exprResult.mType->GetByteCount()))) + // val += StrFormat("\n:break\t%@", exprResult.mSrcAddress); + + auto checkType = exprResult.mType; + if (checkType->IsObject()) + val += "\n:type\tobject"; + else if (checkType->IsPointer()) + val += "\n:type\tpointer"; + else if (checkType->IsInteger()) + val += "\n:type\tint"; + else if (checkType->IsFloat()) + val += "\n:type\tfloat"; + } + + if (dbgState.mHadSideEffects) + val += "\n:sideeffects"; + + auto resultConstant = module->mBfIRBuilder->GetConstant(exprResult.mValue); + if (resultConstant != NULL) + { + auto ceResultTyped = GetAddr(resultConstant); + if (ceResultTyped.mAddr != 0) + val += "\n:canEdit"; + } + + return val; +} + +String CeDebugger::Evaluate(const StringImpl& expr, CeFormatInfo formatInfo, int callStackIdx, int cursorPos, int language, DwEvalExpressionFlags expressionFlags) +{ + BP_ZONE_F("WinDebugger::Evaluate %s", BP_DYN_STR(expr.c_str())); + + AutoCrit autoCrit(mCeMachine->mCritSect); + + if ((expressionFlags & DwEvalExpressionFlag_RawStr) != 0) + { + formatInfo.mRawString = true; + } + + bool valIsAddr = false; + + BfParser* parser = new BfParser(mCompiler->mSystem); + + BfPassInstance bfPassInstance(mCompiler->mSystem); + + auto parseAsType = false; + + auto terminatedExpr = expr; + terminatedExpr.Trim(); + + if (terminatedExpr.EndsWith(">")) + parseAsType = true; + else if ((terminatedExpr.StartsWith("comptype(")) && (!terminatedExpr.Contains('.'))) + parseAsType = true; + + if (!parseAsType) + terminatedExpr += ";"; + if ((terminatedExpr.length() > 2) && (terminatedExpr[0] == '@')) + { + if (terminatedExpr[1] == '!') // Return string as error + { + int errorEnd = (int)terminatedExpr.IndexOf("@!", 2); + if (errorEnd != -1) + return terminatedExpr.Substring(1, errorEnd - 1); + else + return terminatedExpr.Substring(1); + } + else if (terminatedExpr[1] == '>') // Return string as text + { + int errorEnd = (int)terminatedExpr.IndexOf("@>", 2); + if (errorEnd != -1) + return terminatedExpr.Substring(2, errorEnd - 1); + else + return terminatedExpr.Substring(2); + } + } + + parser->SetSource(terminatedExpr.c_str(), (int)terminatedExpr.length()); + parser->Parse(&bfPassInstance); + + BfReducer bfReducer; + bfReducer.mAlloc = parser->mAlloc; + bfReducer.mSystem = mCompiler->mSystem; + bfReducer.mPassInstance = &bfPassInstance; + bfReducer.mVisitorPos = BfReducer::BfVisitorPos(parser->mRootNode); + bfReducer.mVisitorPos.MoveNext(); + bfReducer.mSource = parser; + BfAstNode* exprNode = NULL; + if (parseAsType) + exprNode = bfReducer.CreateTypeRef(parser->mRootNode->mChildArr.GetAs(0)); + else + exprNode = bfReducer.CreateExpression(parser->mRootNode->mChildArr.GetAs(0)); + parser->Close(); + + formatInfo.mCallStackIdx = callStackIdx; + + CePendingExpr* pendingExpr = new CePendingExpr(); + pendingExpr->mParser = parser; + pendingExpr->mCallStackIdx = callStackIdx; + pendingExpr->mCursorPos = cursorPos; + pendingExpr->mExpressionFlags = expressionFlags; + pendingExpr->mExprNode = exprNode; + + BfType* explicitType = NULL; + String formatFlags; + String assignExpr; + int assignExprOffset = -1; + + if ((exprNode != NULL) && (exprNode->GetSrcEnd() < (int)expr.length())) + { + int formatOffset = exprNode->GetSrcEnd(); + while (formatOffset < (int)expr.length()) + { + char c = expr[formatOffset]; + if (c == ' ') + formatOffset++; + else + break; + } + + formatFlags = Trim(expr.Substring(formatOffset)); + bool isComplexType = false; + for (char c : formatFlags) + if (c == '>') + isComplexType = true; + if (isComplexType) + { + //explicitType = dbgModule->FindType(expr); + } + + if ((explicitType == NULL) && (formatFlags.length() > 0)) + { + String errorString = "Invalid expression"; + if (!ParseFormatInfo(formatFlags, &formatInfo, &bfPassInstance, &assignExprOffset, &assignExpr, &errorString)) + { + if (formatInfo.mRawString) + return ""; + bfPassInstance.FailAt(errorString, parser->mSourceData, exprNode->GetSrcEnd(), (int)expr.length() - exprNode->GetSrcEnd()); + formatFlags = ""; + } + if (assignExprOffset != -1) + assignExprOffset += formatOffset; + } + } + + if (assignExpr.length() > 0) + { + String newEvalStr = exprNode->ToString() + " = "; + int errorOffset = (int)newEvalStr.length(); + newEvalStr += assignExpr; + String result = Evaluate(newEvalStr, formatInfo, callStackIdx, cursorPos, language, expressionFlags); + if (result[0] == '!') + { + int tabPos = (int)result.IndexOf('\t'); + if (tabPos > 0) + { + int errorStart = atoi(result.Substring(1, tabPos - 1).c_str()); + if (errorStart >= errorOffset) + { + result = StrFormat("!%d", errorStart - errorOffset + assignExprOffset) + result.Substring(tabPos); + } + } + } + return result; + } + + pendingExpr->mExplitType = explicitType; + pendingExpr->mFormatInfo = formatInfo; + String result = EvaluateContinue(pendingExpr, bfPassInstance); + if (result == "!pending") + { + BF_ASSERT(mDebugPendingExpr == NULL); + if (mDebugPendingExpr != NULL) + { + return "!retry"; // We already have a pending + } + mDebugPendingExpr = pendingExpr; + } + else + delete pendingExpr; + return result; +} + +void CeDebugger::ClearBreakpointCache() +{ + if (!mCeMachine->mDbgPaused) + mCeMachine->mSpecialCheck = true; + mBreakpointFramesDirty = true; + mBreakpointCacheDirty = true; + for (auto kv : mFileInfo) + delete kv.mValue; + mFileInfo.Clear(); +} + +void CeDebugger::UpdateBreakpointAddrs() +{ + for (auto breakpoint : mBreakpoints) + { + breakpoint->mCurBindAddr = 1; + } + + CeFunction* ceFunction = NULL; + if (!mCeMachine->mFunctionIdMap.TryGetValue(mCurDisasmFuncId, &ceFunction)) + return; + + if (ceFunction->mBreakpointVersion != mBreakpointVersion) + UpdateBreakpoints(ceFunction); + + for (auto kv : ceFunction->mBreakpoints) + kv.mValue.mBreakpoint->mCurBindAddr = ((intptr)ceFunction->mId << 32) | kv.mKey; +} + +void CeDebugger::UpdateBreakpointCache() +{ + AutoCrit autoCrit(mCeMachine->mCritSect); + + mBreakpointCacheDirty = false; + if (!mFileInfo.IsEmpty()) + return; + for (int i = 0; i < (int)mBreakpoints.mSize; i++) + { + auto breakpoint = mBreakpoints[i]; + breakpoint->mIdx = i; + String fileName = breakpoint->mFilePath; + fileName = FixPathAndCase(fileName); + CeFileInfo** valuePtr; + CeFileInfo* fileInfo = NULL; + if (mFileInfo.TryAdd(fileName, NULL, &valuePtr)) + { + fileInfo = new CeFileInfo(); + *valuePtr = fileInfo; + } + else + fileInfo = *valuePtr; + fileInfo->mOrderedBreakpoints.Add(breakpoint); + } + + for (auto kv : mFileInfo) + { + kv.mValue->mOrderedBreakpoints.Sort([](CeBreakpoint* lhs, CeBreakpoint* rhs) + { + return lhs->mLineNum < rhs->mLineNum; + }); + } +} + +static int CompareBreakpoint(CeBreakpoint* breakpoint, const int& lineNum) +{ + return breakpoint->mRequestedLineNum - lineNum; +} + +void CeDebugger::UpdateBreakpoints(CeFunction* ceFunction) +{ + AutoCrit autoCrit(mCeMachine->mCritSect); + + UpdateBreakpointCache(); + + ceFunction->UnbindBreakpoints(); + + String path; + int scope = -1; + CeFileInfo* ceFileInfo = NULL; + + BitSet usedBreakpointSet(mBreakpoints.mSize); + + for (auto& emitEntry : ceFunction->mEmitTable) + { + if (emitEntry.mScope != scope) + { + if (emitEntry.mScope != -1) + { + path = FixPathAndCase(ceFunction->mDbgScopes[emitEntry.mScope].mFilePath); + if (!mFileInfo.TryGetValue(path, &ceFileInfo)) + ceFileInfo = NULL; + } + else + ceFileInfo = NULL; + scope = emitEntry.mScope; + } + + if (ceFileInfo != NULL) + { + int idx = ceFileInfo->mOrderedBreakpoints.BinarySearchAlt(emitEntry.mLine, CompareBreakpoint); + if (idx < 0) + idx = ~idx - 1; + + while (idx > 0) + { + auto breakpoint = ceFileInfo->mOrderedBreakpoints[idx - 1]; + if (breakpoint->mLineNum < emitEntry.mLine) + break; + idx--; + } + + int tryBindCount = 0; + int bestRequestedBindLine = 0; + + while ((idx >= 0) && (idx < ceFileInfo->mOrderedBreakpoints.mSize)) + { + auto breakpoint = ceFileInfo->mOrderedBreakpoints[idx]; + if (usedBreakpointSet.IsSet(breakpoint->mIdx)) + { + idx++; + continue; + } + CeBreakpointBind* breakpointBind = NULL; + + if (tryBindCount > 0) + { + if (breakpoint->mRequestedLineNum > bestRequestedBindLine) + break; + } + else + { + int lineDiff = emitEntry.mLine - breakpoint->mLineNum; + if ((lineDiff < 0) || (lineDiff > 4)) + break; + + if ((breakpoint->mHasBound) && (lineDiff != 0)) + break; + + bestRequestedBindLine = breakpoint->mRequestedLineNum; + } + + tryBindCount++; + + int codePos = emitEntry.mCodePos; + if (breakpoint->mInstrOffset > 0) + { + int instrOffsetLeft = breakpoint->mInstrOffset; + while (instrOffsetLeft > 0) + { + auto& opRef = *(CeOp*)(&ceFunction->mCode[codePos]); + int instSize = mCeMachine->GetInstSize(ceFunction, codePos); + codePos += instSize; + instrOffsetLeft--; + } + } + + if (ceFunction->mBreakpoints.TryAdd(codePos, NULL, &breakpointBind)) + { + usedBreakpointSet.Set(breakpoint->mIdx); + breakpoint->mLineNum = emitEntry.mLine; + breakpoint->mHasBound = true; + + auto& opRef = *(CeOp*)(&ceFunction->mCode[codePos]); + breakpointBind->mPrevOpCode = opRef; + breakpointBind->mBreakpoint = breakpoint; + opRef = CeOp_DbgBreak; + } + + idx++; + } + } + } + + ceFunction->mBreakpointVersion = mBreakpointVersion; +} + +CeDbgTypeInfo* CeDebugger::GetDbgTypeInfo(int typeId) +{ + CeDbgTypeInfo* dbgTypeInfo = NULL; + if (mDbgTypeInfoMap.TryAdd(typeId, NULL, &dbgTypeInfo)) + { + auto type = mCeMachine->mCeModule->mContext->FindTypeById(typeId); + if (type == NULL) + { + mDbgTypeInfoMap.Remove(typeId); + return NULL; + } + dbgTypeInfo->mType = type; + + auto typeInst = type->ToTypeInstance(); + if (typeInst != NULL) + { + for (int fieldIdx = 0; fieldIdx < typeInst->mFieldInstances.mSize; fieldIdx++) + { + auto& fieldInst = typeInst->mFieldInstances[fieldIdx]; + if (fieldInst.mDataIdx > 0) + { + while (fieldInst.mDataIdx >= dbgTypeInfo->mFieldOffsets.mSize) + dbgTypeInfo->mFieldOffsets.Add(CeDbgFieldEntry()); + dbgTypeInfo->mFieldOffsets[fieldInst.mDataIdx].mType = fieldInst.mResolvedType; + dbgTypeInfo->mFieldOffsets[fieldInst.mDataIdx].mDataOffset = fieldInst.mDataOffset; + } + + if (fieldInst.mConstIdx != -1) + { + auto constant = typeInst->mConstHolder->GetConstantById(fieldInst.mConstIdx); + if ((constant != NULL) && (BfIRConstHolder::IsInt(constant->mTypeCode))) + { + CeDbgTypeInfo::ConstIntEntry constIntEntry; + constIntEntry.mFieldIdx = fieldIdx; + constIntEntry.mVal = constant->mInt64; + dbgTypeInfo->mConstIntEntries.Add(constIntEntry); + } + } + } + } + + } + return dbgTypeInfo; +} + +CeDbgTypeInfo* CeDebugger::GetDbgTypeInfo(BfIRType irType) +{ + if ((irType.mKind == BfIRTypeData::TypeKind_TypeId) || (irType.mKind == BfIRTypeData::TypeKind_TypeInstId)) + return GetDbgTypeInfo(irType.mId); + if (irType.mKind == BfIRTypeData::TypeKind_TypeInstPtrId) + { + auto type = mCeMachine->mCeModule->mContext->FindTypeById(irType.mId); + if (type->IsObjectOrInterface()) + return GetDbgTypeInfo(irType.mId); + else + return GetDbgTypeInfo(mCeMachine->mCeModule->CreatePointerType(type)->mTypeId); + } + return NULL; +} + +static bool IsNormalChar(uint32 c) +{ + return (c < 0x80); +} + +template +static String IntTypeToString(T val, const StringImpl& name, DwDisplayInfo* displayInfo, CeFormatInfo& formatInfo) +{ + auto intDisplayType = displayInfo->mIntDisplayType; + if (formatInfo.mDisplayType == DwDisplayType_Decimal) + intDisplayType = DwIntDisplayType_Decimal; + else if (formatInfo.mDisplayType == DwDisplayType_HexUpper) + intDisplayType = DwIntDisplayType_HexadecimalUpper; + else if (formatInfo.mDisplayType == DwDisplayType_HexLower) + intDisplayType = DwIntDisplayType_HexadecimalLower; + + if (intDisplayType == DwIntDisplayType_Binary) + { + String binary; + for (int i = 0; i < sizeof(T) * 8; i++) + { + if ((i != 0) && (i % 4 == 0)) + binary = "'" + binary; + + if ((i != 0) && (i % 16 == 0)) + binary = "'" + binary; + + binary = ((val & ((T)1 << i)) ? "1" : "0") + binary; + + } + return StrFormat("0b'%s\n%s", binary.c_str(), name.c_str()); + } + + if (intDisplayType == DwIntDisplayType_Octal) + { + String format; + if (sizeof(T) == 8) + { + format = StrFormat("0o%%lo\n%s", name.c_str()); + } + else + format = StrFormat("0o%%0%do\n%s", sizeof(val) * 2, name.c_str()); + return StrFormat(format.c_str(), (std::make_unsigned::type)(val)); + } + + if (intDisplayType == DwIntDisplayType_HexadecimalUpper) + { + String format; + if (sizeof(T) == 8) + { + format = StrFormat("0x%%l@\n%s", name.c_str()); + } + else + format = StrFormat("0x%%0%dX\n%s", sizeof(val) * 2, name.c_str()); + return StrFormat(format.c_str(), (std::make_unsigned::type)(val)); + } + + //TODO: Implement HexadecimalLower + if (intDisplayType == DwIntDisplayType_HexadecimalLower) + { + String format; + if (sizeof(T) == 8) + { + format = StrFormat("0x%%l@\n%s", name.c_str()); + } + else + format = StrFormat("0x%%0%dX\n%s", sizeof(val) * 2, name.c_str()); + return StrFormat(format.c_str(), (std::make_unsigned::type)(val)); + } + + if (std::is_unsigned::value) + { + if (sizeof(T) == 8) + { + if (val > 0x7FFFFFFFF) + return StrFormat("%llu\n%s\n:editVal\t%lluUL", val, name.c_str(), val); + else + return StrFormat("%llu\n%s", val, name.c_str()); + } + else + return StrFormat("%u\n%s", val, name.c_str()); + } + else + { + if (sizeof(T) == 8) + { + if ((val > 0x7FFFFFFFF) || (val < -0x80000000LL)) + return StrFormat("%lld\n%s\n:editVal\t%lldL", val, name.c_str(), val); + else + return StrFormat("%lld\n%s", val, name.c_str(), val); + } + else + return StrFormat("%d\n%s", val, name.c_str()); + } +} + +DwDisplayInfo* CeDebugger::GetDisplayInfo(const StringImpl& referenceId) +{ + DwDisplayInfo* displayInfo = &mDebugManager->mDefaultDisplayInfo; + if (!referenceId.empty()) + { + mDebugManager->mDisplayInfos.TryGetValue(referenceId, &displayInfo); + } + return displayInfo; +} + +String CeDebugger::GetMemberList(BfType* type, addr_ce addr, addr_ce addrInst, bool isStatic) +{ + auto typeInst = type->ToTypeInstance(); + if (typeInst == NULL) + return ""; + + auto module = typeInst->mModule; + + String retVal; + int fieldCount = 0; + + if ((typeInst->mBaseType != NULL) && + (!typeInst->mBaseType->IsInstanceOf(mCompiler->mBfObjectTypeDef)) && + (!typeInst->mBaseType->IsInstanceOf(mCompiler->mValueTypeTypeDef))) + { + retVal += StrFormat("[base]\tthis,this=%d@0x%X, nd, na, nv", typeInst->mBaseType->mTypeId, addr); + fieldCount++; + } + + auto ceContext = mCompiler->mCEMachine->mCurContext; + bool didStaticCtor = ceContext->mStaticCtorExecSet.Contains(type->mTypeId); + + bool hasStaticFields = false; + for (auto& fieldInst : typeInst->mFieldInstances) + { + auto fieldDef = fieldInst.GetFieldDef(); + if (fieldDef == NULL) + continue; + + if (fieldDef->mIsStatic != isStatic) + { + if (fieldDef->mIsStatic) + hasStaticFields = true; + continue; + } + + if (fieldCount > 0) + retVal += "\n"; + + retVal += fieldDef->mName; + if (fieldDef->mIsStatic) + { + if (didStaticCtor) + retVal += StrFormat("\tcomptype(%d).%s", type->mTypeId, fieldDef->mName.c_str()); + else + retVal += StrFormat("\tcomptype(%d).%s", type->mTypeId, fieldDef->mName.c_str()); + } + else + { + retVal += "\t"; + retVal += fieldDef->mName; + retVal += StrFormat(",this=%d@0x%X", typeInst->mTypeId, addrInst); + } + + fieldCount++; + } + + if (hasStaticFields) + { + if (fieldCount > 0) + retVal += "\n"; + + retVal += StrFormat("Static values\tcomptype(%d)", typeInst->mTypeId); + } + + return retVal; +} + +bool CeDebugger::ParseFormatInfo(const StringImpl& formatInfoStr, CeFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExprString, String* errorString, BfTypedValue contextTypedValue) +{ + String formatFlags = formatInfoStr; + if (assignExprOffset != NULL) + *assignExprOffset = -1; + + while (formatFlags.length() > 0) + { + formatFlags = Trim(formatFlags); + if (formatFlags.IsEmpty()) + break; + if (formatFlags[0] != ',') + { + return false; + } + else + { + int nextComma = (int)formatFlags.IndexOf(',', 1); + int quotePos = (int)formatFlags.IndexOf('"', 1); + if ((quotePos != -1) && (quotePos < nextComma)) + { + int nextQuotePos = (int)formatFlags.IndexOf('"', quotePos + 1); + if (nextQuotePos != -1) + nextComma = (int)formatFlags.IndexOf(',', nextQuotePos + 1); + } + if (nextComma == -1) + nextComma = (int)formatFlags.length(); + + String formatCmd = formatFlags.Substring(1, nextComma - 1); + formatCmd = Trim(formatCmd); + bool hadError = false; + + if (strncmp(formatCmd.c_str(), "this=", 5) == 0) + { + formatCmd = formatFlags.Substring(1); + formatCmd = Trim(formatCmd); + String thisExpr = formatCmd.Substring(5); + if (thisExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, thisExpr, formatInfo); + formatInfo->mExplicitThis = dbgEvaluationContext.EvaluateInContext(contextTypedValue); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + formatFlags = thisExpr.Substring(dbgEvaluationContext.mExprString.GetLength()); + continue; + } + else if (strncmp(formatCmd.c_str(), "count=", 6) == 0) + { + formatCmd = formatFlags.Substring(1); + formatCmd = Trim(formatCmd); + String countExpr = formatCmd.Substring(6); + if (countExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, countExpr, formatInfo); + BfTypedValue countValue = dbgEvaluationContext.EvaluateInContext(contextTypedValue); + if ((countValue) && (countValue.mType->IsInteger())) + formatInfo->mOverrideCount = (intptr)ValueToInt(countValue); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + formatFlags = countExpr.Substring(dbgEvaluationContext.mExprString.GetLength()); + continue; + } + else if (strncmp(formatCmd.c_str(), "maxcount=", 9) == 0) + { + formatCmd = formatFlags.Substring(1); + formatCmd = Trim(formatCmd); + String countExpr = formatCmd.Substring(9); + if (countExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, countExpr, formatInfo); + BfTypedValue countValue = dbgEvaluationContext.EvaluateInContext(contextTypedValue); + if ((countValue) && (countValue.mType->IsInteger())) + formatInfo->mMaxCount = (intptr)ValueToInt(countValue); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + formatFlags = countExpr.Substring(dbgEvaluationContext.mExprString.GetLength()); + continue; + } + else if (strncmp(formatCmd.c_str(), "arraysize=", 10) == 0) + { + formatCmd = formatFlags.Substring(1); + formatCmd = Trim(formatCmd); + String countExpr = formatCmd.Substring(10); + if (countExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, countExpr, formatInfo); + BfTypedValue countValue = dbgEvaluationContext.EvaluateInContext(contextTypedValue); + if ((countValue) && (countValue.mType->IsInteger())) + formatInfo->mArrayLength = (intptr)ValueToInt(countValue); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + formatFlags = countExpr.Substring(dbgEvaluationContext.mExprString.GetLength()); + continue; + } + else if (strncmp(formatCmd.c_str(), "assign=", 7) == 0) + { + formatCmd = formatFlags.Substring(1); + formatCmd = Trim(formatCmd); + String assignExpr = formatCmd.Substring(7); + if (assignExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, assignExpr, formatInfo); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + if (assignExprOffset != NULL) + { + //TODO: Keep track of the offset directly, this is a hack + *assignExprOffset = (int)formatInfoStr.IndexOf("assign=") + 7; + } + if (assignExprString != NULL) + *assignExprString = dbgEvaluationContext.mExprNode->ToString(); + formatFlags = assignExpr.Substring(dbgEvaluationContext.mExprNode->GetSrcEnd()); + continue; + } + else if (strncmp(formatCmd.c_str(), "refid=", 6) == 0) + { + formatInfo->mReferenceId = formatCmd.Substring(6); + if (formatInfo->mReferenceId[0] == '\"') + formatInfo->mReferenceId = formatInfo->mReferenceId.Substring(1, formatInfo->mReferenceId.length() - 2); + } + else if (strncmp(formatCmd.c_str(), "_=", 2) == 0) + { + formatInfo->mSubjectExpr = formatCmd.Substring(2); + if (formatInfo->mSubjectExpr[0] == '\"') + formatInfo->mSubjectExpr = formatInfo->mSubjectExpr.Substring(1, formatInfo->mSubjectExpr.length() - 2); + } + else if (strncmp(formatCmd.c_str(), "expectedType=", 13) == 0) + { + formatInfo->mExpectedType = formatCmd.Substring(13); + if (formatInfo->mExpectedType[0] == '\"') + formatInfo->mExpectedType = formatInfo->mExpectedType.Substring(1, formatInfo->mExpectedType.length() - 2); + } + else if (strncmp(formatCmd.c_str(), "namespaceSearch=", 16) == 0) + { + formatInfo->mNamespaceSearch = formatCmd.Substring(16); + if (formatInfo->mNamespaceSearch[0] == '\"') + formatInfo->mNamespaceSearch = formatInfo->mNamespaceSearch.Substring(1, formatInfo->mNamespaceSearch.length() - 2); + } + else if (formatCmd == "d") + { + formatInfo->mDisplayType = DwDisplayType_Decimal; + } + else if (formatCmd == "x") + { + formatInfo->mDisplayType = DwDisplayType_HexLower; + } + else if (formatCmd == "X") + { + formatInfo->mDisplayType = DwDisplayType_HexUpper; + } + else if (formatCmd == "s") + { + formatInfo->mHidePointers = true; + formatInfo->mDisplayType = DwDisplayType_Ascii; + } + else if (formatCmd == "s8") + { + formatInfo->mHidePointers = true; + formatInfo->mDisplayType = DwDisplayType_Utf8; + } + else if (formatCmd == "s16") + { + formatInfo->mHidePointers = true; + formatInfo->mDisplayType = DwDisplayType_Utf16; + } + else if (formatCmd == "s32") + { + formatInfo->mHidePointers = true; + formatInfo->mDisplayType = DwDisplayType_Utf32; + } + else if (formatCmd == "nd") + { + formatInfo->mIgnoreDerivedClassInfo = true; + } + else if (formatCmd == "na") + { + formatInfo->mHidePointers = true; + } + else if (formatCmd == "nm") + { + formatInfo->mNoMembers = true; + } + else if (formatCmd == "ne") + { + formatInfo->mNoEdit = true; + } + else if (formatCmd == "nv") + { + formatInfo->mNoVisualizers = true; + } + else if (formatCmd == "rawStr") + { + formatInfo->mRawString = true; + } + else if (((!formatCmd.IsEmpty()) && ((formatCmd[0] >= '0') && (formatCmd[0] <= '9'))) || + (formatCmd.StartsWith("("))) + { + String countExpr = formatCmd; + if (countExpr.empty()) + break; + CeEvaluationContext dbgEvaluationContext(this, countExpr, formatInfo); + BfTypedValue countValue = dbgEvaluationContext.EvaluateInContext(contextTypedValue); + if ((countValue) && (countValue.mType->IsInteger())) + formatInfo->mArrayLength = (intptr)ValueToInt(countValue); + if (dbgEvaluationContext.HadError()) + { + if (errorString != NULL) + *errorString = dbgEvaluationContext.GetErrorStr(); + return false; + } + formatFlags = dbgEvaluationContext.mExprString; + continue; + } + else + hadError = true; + + if (hadError) + { + if (errorString != NULL) + *errorString = "Invalid format flags"; + return false; + } + + formatFlags = formatFlags.Substring(nextComma); + } + } + return true; +} + +String CeDebugger::MaybeQuoteFormatInfoParam(const StringImpl& str) +{ + bool needsQuote = false; + for (int i = 0; i < (int)str.length(); i++) + { + char c = str[i]; + if (c == ',') + needsQuote = true; + } + if (!needsQuote) + return str; + + String qStr = "\""; + qStr += str; + qStr += "\""; + return qStr; +} + +BfTypedValue CeDebugger::EvaluateInContext(const BfTypedValue& contextTypedValue, const StringImpl& subExpr, CeFormatInfo* formatInfo, String* outReferenceId, String* outErrors) +{ + CeEvaluationContext dbgEvaluationContext(this, subExpr, formatInfo, contextTypedValue); +// if (formatInfo != NULL) +// { +// dbgEvaluationContext.mDbgExprEvaluator->mSubjectExpr = formatInfo->mSubjectExpr; +// } + //dbgEvaluationContext.mDbgExprEvaluator->mReferenceId = outReferenceId; + + SetAndRestoreValue prevEvalContext(mCurEvaluationContext, &dbgEvaluationContext); + + //mCountResultOverride = -1; + auto result = dbgEvaluationContext.EvaluateInContext(contextTypedValue); +// if ((formatInfo != NULL) && (dbgEvaluationContext.mDbgExprEvaluator->mCountResultOverride != -1)) +// formatInfo->mOverrideCount = dbgEvaluationContext.mDbgExprEvaluator->mCountResultOverride; + if (dbgEvaluationContext.mPassInstance->HasFailed()) + { + if (outErrors != NULL) + { + int errIdx = 0; + for (auto err : dbgEvaluationContext.mPassInstance->mErrors) + { + if (errIdx > 0) + (*outErrors) += "\n"; + (*outErrors) += err->mError; + errIdx++; + } + } + return BfTypedValue(); + } + return result; +} + +void CeDebugger::DbgVisFailed(DebugVisualizerEntry* debugVis, const StringImpl& evalString, const StringImpl& errors) +{ + bool onlyMemError = errors.StartsWith("Failed to read") && !errors.Contains('\n'); + if ((!debugVis->mShowedError) && (!onlyMemError)) + { + debugVis->mShowedError = true; + String errStr = StrFormat("DbgVis '%s' failed while evaluating condition '%s'\n", debugVis->mName.c_str(), evalString.c_str()); + String spacedErrors = errors; + spacedErrors.Insert(0, " "); + spacedErrors.Replace("\n", "\n "); + errStr += spacedErrors; + OutputMessage(errStr); + } +} + +bool CeDebugger::EvalCondition(DebugVisualizerEntry* debugVis, BfTypedValue typedVal, CeFormatInfo& formatInfo, const StringImpl& condition, const Array& dbgVisWildcardCaptures, String& errorStr) +{ + auto ceModule = mCeMachine->mCeModule; + + CeFormatInfo displayStrFormatInfo = formatInfo; + displayStrFormatInfo.mHidePointers = false; + displayStrFormatInfo.mRawString = false; + + String errors; + const String conditionStr = mDebugManager->mDebugVisualizers->DoStringReplace(condition, dbgVisWildcardCaptures); + BfTypedValue evalResult = EvaluateInContext(typedVal, conditionStr, &displayStrFormatInfo, NULL, &errors); + if ((!evalResult) || (!evalResult.mType->IsBoolean())) + { + if (formatInfo.mRawString) + return false; + + errorStr += ""; + DbgVisFailed(debugVis, conditionStr, errors); + return false; + } + + evalResult = ceModule->LoadValue(evalResult); + if (auto constant = ceModule->mBfIRBuilder->GetConstant(evalResult.mValue)) + { + if (constant->mTypeCode == BfTypeCode_Boolean) + return constant->mBool; + } + + return false; +} + +String CeDebugger::GetArrayItems(DebugVisualizerEntry* debugVis, BfType* valueType, BfTypedValue& curNode, int& count, String* outContinuationData) +{ + CeEvaluationContext conditionEvaluationContext(this, debugVis->mCondition); + auto ceModule = mCeMachine->mCeModule; + + String addrs; + + bool checkLeft = true; + + addr_ce curNodeAddr = 0; + + int usedCount = 0; + while (usedCount < count) + { + if ((!curNode) || (!curNode.mType->IsPointer())) + break; + curNode = ceModule->LoadValue(curNode); + + BfTypedValue condVal = conditionEvaluationContext.EvaluateInContext(curNode); + if (!condVal) + break; + + auto ceTypedVal = GetAddr(curNode); + if (!ceTypedVal) + break; + + if (ValueToInt(condVal) != 0) + { + auto val = curNode; + if (valueType == NULL) + { + //String typeAddr = val.mType->ToStringRaw(); + String typeAddr = StrFormat("comptype(%d)", val.mType->mTypeId); + // RPad + typeAddr.Append(' ', sizeof(addr_ce) * 2 - (int)typeAddr.length()); + addrs += typeAddr; + } + + String addr = EncodeDataPtr(ceTypedVal.mAddr, false); + addrs += addr; + usedCount++; + } + auto elemType = curNode.mType->GetUnderlyingType(); + curNodeAddr = ceTypedVal.mAddr + elemType->GetStride(); + curNode.mValue = ceModule->mBfIRBuilder->CreateIntToPtr(curNodeAddr, ceModule->mBfIRBuilder->MapType(curNode.mType)); + } + count = usedCount; + + if (outContinuationData != NULL) + { + *outContinuationData += EncodeDataPtr(debugVis, false) + EncodeDataPtr(valueType, false) + + EncodeDataPtr(curNode.mType, false) + EncodeDataPtr(curNodeAddr, false); + } + + return addrs; +} + +String CeDebugger::GetLinkedListItems(DebugVisualizerEntry* debugVis, addr_ce endNodePtr, BfType* valueType, BfTypedValue& curNode, int& count, String* outContinuationData) +{ + CeEvaluationContext nextEvaluationContext(this, debugVis->mNextPointer); + CeEvaluationContext valueEvaluationContext(this, debugVis->mValuePointer); + + String addrs; + + bool checkLeft = true; + + //TODO; +// int mapIdx; +// for (mapIdx = 0; mapIdx < count; mapIdx++) +// { +// if (curNode.mPtr == endNodePtr) +// break; +// BfTypedValue val = valueEvaluationContext.EvaluateInContext(curNode); +// if (!val) +// break; +// if (val.mPtr == 0) +// break; +// +// if (valueType == NULL) +// { +// String typeAddr = val.mType->ToStringRaw(); +// // RPad +// typeAddr.Append(' ', sizeof(addr_ce) * 2 - typeAddr.length()); +// addrs += typeAddr; +// } +// +// String addr = EncodeDataPtr(val.mPtr, false); +// addrs += addr; +// +// curNode = nextEvaluationContext.EvaluateInContext(curNode); +// } +// count = mapIdx; +// +// if (outContinuationData != NULL) +// { +// *outContinuationData += EncodeDataPtr(debugVis, false) + EncodeDataPtr(endNodePtr, false) + EncodeDataPtr(valueType, false) + +// EncodeDataPtr(curNode.mType, false) + EncodeDataPtr(curNode.mPtr, false); +// } + + return addrs; +} + +String CeDebugger::GetDictionaryItems(DebugVisualizerEntry* debugVis, BfTypedValue dictValue, int bucketIdx, int nodeIdx, int& count, String* outContinuationData) +{ + CeEvaluationContext nextEvaluationContext(this, debugVis->mNextPointer); + + BfTypedValue bucketsPtr = EvaluateInContext(dictValue, debugVis->mBuckets); + BfTypedValue entriesPtr = EvaluateInContext(dictValue, debugVis->mEntries); + if ((!bucketsPtr) || (!entriesPtr)) + { + count = -1; + return ""; + } + + String addrs; + + //TODO: +// int entrySize = entriesPtr.mType->mTypeParam->GetStride(); +// int bucketIdxSize = bucketsPtr.mType->mTypeParam->GetStride(); +// +// bool checkLeft = true; +// +// int encodeCount = 0; +// while (encodeCount < count) +// { +// if (nodeIdx != -1) +// { +// BfTypedValue entryValue; +// entryValue.mSrcAddress = entriesPtr.mPtr + (nodeIdx * entrySize); +// entryValue.mType = entriesPtr.mType->mTypeParam; +// +// addrs += EncodeDataPtr(entryValue.mSrcAddress, false); +// +// BfTypedValue nextValue = nextEvaluationContext.EvaluateInContext(entryValue); +// if ((!nextValue) || (!nextValue.mType->IsInteger())) +// { +// break; +// } +// +// nodeIdx = (int)nextValue.GetInt64(); +// encodeCount++; +// } +// else +// { +// if (bucketIdxSize == 4) +// nodeIdx = ReadMemory(bucketsPtr.mPtr + bucketIdx * sizeof(int32)); +// else +// nodeIdx = (int)ReadMemory(bucketsPtr.mPtr + bucketIdx * sizeof(int64)); +// bucketIdx++; +// } +// } +// +// count = encodeCount; +// +// if (outContinuationData != NULL) +// { +// *outContinuationData += EncodeDataPtr(debugVis, false) + EncodeDataPtr(dictValue.mType, false) + EncodeDataPtr(dictValue.mSrcAddress, false) + +// EncodeDataPtr((addr_ce)bucketIdx, false) + EncodeDataPtr((addr_ce)nodeIdx, false); +// } + + return addrs; +} + +String CeDebugger::GetTreeItems(DebugVisualizerEntry* debugVis, Array& parentList, BfType*& valueType, BfTypedValue& curNode, int count, String* outContinuationData) +{ + CeEvaluationContext leftEvaluationContext(this, debugVis->mLeftPointer); + CeEvaluationContext rightEvaluationContext(this, debugVis->mRightPointer); + CeEvaluationContext valueEvaluationContext(this, debugVis->mValuePointer); + + CeEvaluationContext conditionEvaluationContext(this, debugVis->mCondition); + + String addrs; + + //TODO: +// bool checkLeft = true; +// +// if ((curNode.mPtr & 2) != 0) // Flag from continuation +// { +// checkLeft = false; +// curNode.mPtr &= (addr_ce)~2; +// } +// +// HashSet seenAddrs; +// +// for (int mapIdx = 0; mapIdx < count; mapIdx++) +// { +// BfTypedValue readNode; +// while (true) +// { +// bool checkNode = (curNode.mPtr & 1) == 0; +// +// readNode = curNode; +// readNode.mPtr &= (addr_ce)~1; +// +// if (checkLeft) +// { +// BfTypedValue leftValue = leftEvaluationContext.EvaluateInContext(readNode); +// bool isEmpty = leftValue.mPtr == NULL; +// if ((leftValue) && (conditionEvaluationContext.HasExpression())) +// { +// auto condValue = conditionEvaluationContext.EvaluateInContext(leftValue); +// if (condValue) +// isEmpty = !condValue.mBool; +// } +// if (isEmpty) +// { +// checkLeft = false; +// break; // Handle node +// } +// +// parentList.push_back(curNode.mPtr); +// curNode = leftValue; +// } +// else if (checkNode) +// { +// break; // Handle node +// } +// else +// { +// BfTypedValue rightValue = rightEvaluationContext.EvaluateInContext(readNode); +// bool isEmpty = rightValue.mPtr == NULL; +// if ((rightValue) && (conditionEvaluationContext.HasExpression())) +// { +// auto condValue = conditionEvaluationContext.EvaluateInContext(rightValue); +// if (condValue) +// isEmpty = !condValue.mBool; +// } +// if (!isEmpty) +// { +// curNode = rightValue; +// checkLeft = true; +// } +// else +// { +// if (parentList.size() == 0) +// { +// // Failed +// break; +// } +// +// curNode.mPtr = parentList.back(); +// parentList.pop_back(); +// continue; // Don't check against seenAddrs +// } +// } +// +// if (!seenAddrs.Add(curNode.mPtr)) +// { +// // Failed! +// return ""; +// } +// } +// +// +// BfTypedValue val = valueEvaluationContext.EvaluateInContext(readNode); +// if (valueType == NULL) +// valueType = val.mType; +// +// String addr = EncodeDataPtr(val.mPtr, false); +// addrs += addr; +// +// curNode.mPtr |= 1; // Node handled +// } +// +// if (!checkLeft) +// curNode.mPtr |= 2; +// +// if (outContinuationData != NULL) +// { +// *outContinuationData += EncodeDataPtr(debugVis, false) + EncodeDataPtr(valueType, false) + EncodeDataPtr(curNode.mType, false) + EncodeDataPtr(curNode.mPtr, false); +// for (auto parent : parentList) +// *outContinuationData += EncodeDataPtr(parent, false); +// } + + return addrs; +} + +String CeDebugger::GetCollectionContinuation(const StringImpl& continuationData, int callStackIdx, int count) +{ + if (!mCeMachine->mDbgPaused) + return ""; + + auto ceModule = mCeMachine->mCeModule; + const char* dataPtr = continuationData.c_str(); + DebugVisualizerEntry* debugVis = (DebugVisualizerEntry*)DecodeLocalDataPtr(dataPtr); + + if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_TreeItems) + { + //TODO: +// DbgType* valueType = (DbgType*)DecodeLocalDataPtr(dataPtr); +// BfTypedValue curNode; +// curNode.mType = (DbgType*)DecodeLocalDataPtr(dataPtr); +// curNode.mPtr = DecodeTargetDataPtr(dataPtr); +// +// Array parentList; +// String newContinuationData; +// while (*dataPtr != 0) +// parentList.push_back(DecodeTargetDataPtr(dataPtr)); +// +// String retVal = GetTreeItems(dbgCompileUnit, debugVis, parentList, valueType, curNode, count, &newContinuationData); +// retVal += "\n" + newContinuationData; +// return retVal; + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_LinkedList) + { + //TODO: +// addr_ce endNodePtr = DecodeTargetDataPtr(dataPtr); +// DbgType* valueType = (DbgType*)DecodeLocalDataPtr(dataPtr); +// BfTypedValue curNode; +// curNode.mType = (DbgType*)DecodeLocalDataPtr(dataPtr); +// curNode.mPtr = DecodeTargetDataPtr(dataPtr); +// +// String newContinuationData; +// +// if (count < 0) +// count = 3; +// +// String retVal = GetLinkedListItems(dbgCompileUnit, debugVis, endNodePtr, valueType, curNode, count, &newContinuationData); +// retVal += "\n" + newContinuationData; +// return retVal; + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_Array) + { + BfType* valueType = (BfType*)DecodeLocalDataPtr(dataPtr); + + auto nodeType = (BfType*)DecodeLocalDataPtr(dataPtr); + BfTypedValue curNode = BfTypedValue( + ceModule->mBfIRBuilder->CreateIntToPtr(DecodeTargetDataPtr(dataPtr), ceModule->mBfIRBuilder->MapType(nodeType)), + nodeType); + + String newContinuationData; + + if (count < 0) + count = 3; + + String retVal = GetArrayItems(debugVis, valueType, curNode, count, &newContinuationData); + retVal += "\n" + newContinuationData; + return retVal; + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_Dictionary) + { + //TODO: +// BfTypedValue dictValue; +// dictValue.mType = (DbgType*)DecodeLocalDataPtr(dataPtr); +// dictValue.mSrcAddress = DecodeTargetDataPtr(dataPtr); +// +// int bucketIdx = (int)DecodeTargetDataPtr(dataPtr); +// int nodeIdx = (int)DecodeTargetDataPtr(dataPtr); +// +// String newContinuationData; +// String retVal = GetDictionaryItems(dbgCompileUnit, debugVis, dictValue, bucketIdx, nodeIdx, count, &newContinuationData); +// retVal += "\n" + newContinuationData; +// return retVal; + } + + return ""; +} + +CeTypedValue CeDebugger::GetAddr(BfConstant* constant) +{ + auto module = mCeMachine->mCeModule; + auto ceContext = mCeMachine->mCurContext; + + if (constant->mConstType == BfConstType_GlobalVar) + { + auto globalVar = (BfGlobalVar*)constant; + + String varName(globalVar->mName); + + if (varName.StartsWith("__bfStrObj")) + { + int stringId = atoi(varName.c_str() + 10); + auto addr = ceContext->GetString(stringId); + return CeTypedValue(addr, globalVar->mType); + } + else if (varName.StartsWith("__bfStrData")) + { + auto stringType = module->ResolveTypeDef(module->mCompiler->mStringTypeDef)->ToTypeInstance(); + int stringId = atoi(varName.c_str() + 11); + auto addr = ceContext->GetString(stringId) + stringType->mInstSize; + return CeTypedValue(addr, globalVar->mType); + } + + CeStaticFieldInfo* fieldInfo = NULL; + if (ceContext->mStaticFieldMap.TryAdd(globalVar->mName, NULL, &fieldInfo)) + { + auto dbgTypeInfo = GetDbgTypeInfo(globalVar->mType); + if (dbgTypeInfo != NULL) + { + uint8* ptr = ceContext->CeMalloc(dbgTypeInfo->mType->mSize); + if (dbgTypeInfo->mType->mSize > 0) + memset(ptr, 0, dbgTypeInfo->mType->mSize); + fieldInfo->mAddr = (addr_ce)(ptr - ceContext->mMemory.mVals); + } + else + fieldInfo->mAddr = 0; + } + return CeTypedValue(fieldInfo->mAddr, globalVar->mType); + } + else if (constant->mConstType == BfConstType_AggCE) + { + auto aggCE = (BfConstantAggCE*)constant; + return CeTypedValue(aggCE->mCEAddr, aggCE->mType); + } + else if (constant->mConstType == BfConstType_BitCast) + { + auto constBitCast = (BfConstantBitCast*)constant; + auto val = GetAddr(module->mBfIRBuilder->GetConstantById(constBitCast->mTarget)); + if (!val) + return val; + return CeTypedValue(val.mAddr, constBitCast->mToType); + } + else if (constant->mConstType == BfConstType_IntToPtr) + { + auto fromPtrToInt = (BfConstantIntToPtr*)constant; + auto val = GetAddr(module->mBfIRBuilder->GetConstantById(fromPtrToInt->mTarget)); + if (!val) + return val; + return CeTypedValue(val.mAddr, fromPtrToInt->mToType); + } + else if (constant->mConstType == BfConstType_GEP32_1) + { + auto gepConst = (BfConstantGEP32_1*)constant; + + auto constant = module->mBfIRBuilder->GetConstantById(gepConst->mTarget); + auto typedVal = GetAddr(constant); + if (!typedVal) + return CeTypedValue(); + + auto dbgTypeInfo = GetDbgTypeInfo(typedVal.mType); + if (dbgTypeInfo == NULL) + return CeTypedValue(); + + if (!dbgTypeInfo->mType->IsPointer()) + { + NOP; + } + + auto addr = typedVal.mAddr; + + if (gepConst->mIdx0 != 0) + addr += gepConst->mIdx0 * dbgTypeInfo->mType->GetUnderlyingType()->GetStride(); + + return CeTypedValue(addr, module->mBfIRBuilder->MapType(dbgTypeInfo->mType)); + } + else if (constant->mConstType == BfConstType_GEP32_2) + { + auto gepConst = (BfConstantGEP32_2*)constant; + + auto constant = module->mBfIRBuilder->GetConstantById(gepConst->mTarget); + auto typedVal = GetAddr(constant); + if (!typedVal.mAddr) + return CeTypedValue(); + + auto dbgTypeInfo = GetDbgTypeInfo(typedVal.mType); + + if ((dbgTypeInfo != NULL) && (dbgTypeInfo->mType->IsPointer())) + dbgTypeInfo = GetDbgTypeInfo(dbgTypeInfo->mType->GetUnderlyingType()->mTypeId); + + if (dbgTypeInfo == NULL) + return CeTypedValue(); + + auto addr = typedVal.mAddr; + + if (gepConst->mIdx0 != 0) + addr += gepConst->mIdx0 * dbgTypeInfo->mType->GetStride(); + if (gepConst->mIdx1 != 0) + addr += dbgTypeInfo->mFieldOffsets[gepConst->mIdx1].mDataOffset; + auto ptrType = module->CreatePointerType(dbgTypeInfo->mFieldOffsets[gepConst->mIdx1].mType); + return CeTypedValue(addr, module->mBfIRBuilder->MapType(ptrType)); + } + else if ((constant->mTypeCode == BfTypeCode_Int32) || + (constant->mTypeCode == BfTypeCode_Int64) || + (constant->mTypeCode == BfTypeCode_IntPtr)) + { + return CeTypedValue((addr_ce)constant->mInt64, module->mBfIRBuilder->GetPrimitiveType(constant->mTypeCode)); + } + + return CeTypedValue(); +} + +CeTypedValue CeDebugger::GetAddr(const BfTypedValue typedVal) +{ + auto constant = mCeMachine->mCeModule->mBfIRBuilder->GetConstant(typedVal.mValue); + if (constant == NULL) + return CeTypedValue(); + return GetAddr(constant); +} + +#define GET_FROM(ptr, T) *((T*)(ptr += sizeof(T)) - 1) + +String CeDebugger::ReadString(BfTypeCode charType, intptr addr, intptr maxLength, CeFormatInfo& formatInfo) +{ + int origMaxLength = (int)maxLength; + if (addr == 0) + return ""; + + BP_ZONE("WinDebugger::ReadString"); + + String retVal = "\""; + bool wasTerminated = false; + String valString; + intptr maxShowSize = 255; + + if (maxLength == -1) + maxLength = formatInfo.mOverrideCount; + else if (formatInfo.mOverrideCount != -1) + maxLength = BF_MIN(formatInfo.mOverrideCount, maxLength); + if (formatInfo.mMaxCount != -1) + maxLength = BF_MIN(formatInfo.mMaxCount, maxLength); + + if (maxLength == -1) + maxLength = 8 * 1024 * 1024; // Is 8MB crazy? + if (!formatInfo.mRawString) + maxLength = BF_MIN(maxLength, maxShowSize); + + //EnableMemCache(); + bool readFailed = false; + intptr strPtr = addr; + + int charLen = 1; + if (charType == BfTypeCode_Char16) + charLen = 2; + else if (charType == BfTypeCode_Char32) + charLen = 4; + + bool isUTF8 = formatInfo.mDisplayType == DwDisplayType_Utf8; + + int readSize = BF_MIN(1024, (int)maxLength * charLen); + uint8 buf[1024]; + uint8* bufPtr = NULL; + uint8* bufEnd = NULL; + bool hasHighAscii = false; + + int i; + for (i = 0; i < maxLength; i++) + { + if (bufPtr >= bufEnd) + { + while (true) + { + if (readSize < charLen) + { + readFailed = true; + break; + } + + if (ReadMemory(strPtr, readSize, buf)) + break; + + readSize /= 2; + } + if (readFailed) + break; + + bufPtr = buf; + bufEnd = buf + readSize; + } + + switch (charLen) + { + case 1: + { + char c = GET_FROM(bufPtr, char); + if ((c != 0) || (formatInfo.mOverrideCount != -1)) + { + if ((uint8)c >= 0x80) + hasHighAscii = true; + valString.Append(c); + } + else + wasTerminated = true; + } + break; + case 2: + { + uint16 c16 = GET_FROM(bufPtr, uint16); + if ((c16 != 0) || (formatInfo.mOverrideCount != -1)) + { + char str[8]; + u8_toutf8(str, 8, c16); + valString += str; + } + else + wasTerminated = true; + } + break; + case 4: + { + uint32 c32 = GET_FROM(bufPtr, uint32); + if ((c32 != 0) || (formatInfo.mOverrideCount != -1)) + { + char str[8]; + u8_toutf8(str, 8, c32); + valString += str; + } + else + wasTerminated = true; + } + break; + } + + if ((wasTerminated) && (formatInfo.mOverrideCount != -1)) + { + valString += '\x00'; + wasTerminated = false; + } + + if ((wasTerminated) || (readFailed)) + { + break; + } + strPtr += charLen; + } + //DisableMemCache(); + + if (formatInfo.mOverrideCount != -1) + { + if (i == formatInfo.mOverrideCount) + wasTerminated = true; + } + + if (strPtr == addr + origMaxLength) + wasTerminated = true; + + if (valString.length() == formatInfo.mOverrideCount) + wasTerminated = true; + + // if (formatInfo.mDisplayType == DwDisplayType_Ascii) + // { + // // Our encoding for retVal is already assumed to be UTF8, so the special case here actually Ascii + // valString = UTF8Encode(ToWString(valString)); + // } + + if (formatInfo.mRawString) + { + if ((formatInfo.mDisplayType == DwDisplayType_Utf8) || (!hasHighAscii)) + return valString; + + String utf8Str; + for (int i = 0; i < (int)valString.length(); i++) + { + char c = valString[i]; + if ((uint8)c >= 0x80) + { + utf8Str += (char)(0xC0 | (((uint8)c & 0xFF) >> 6)); + utf8Str += (char)(0x80 | ((uint8)c & 0x3F)); + } + else + utf8Str += c; + } + return utf8Str; + } + + if ((readFailed) && (valString.IsEmpty())) + return "< Failed to read string >"; + + retVal += SlashString(valString, true, true, true); + + // We could go over 'maxShowSize' if we have a lot of slashed chars. An uninitialized string can be filled with '\xcc' chars + if ((!formatInfo.mRawString) && ((int)retVal.length() > maxShowSize)) + { + retVal = retVal.Substring(0, maxShowSize); + wasTerminated = false; + } + + if (wasTerminated) + retVal += "\""; + else + retVal += "..."; + + return retVal; +} + +void CeDebugger::ProcessEvalString(BfTypedValue useTypedValue, String& evalStr, String& displayString, CeFormatInfo& formatInfo, DebugVisualizerEntry* debugVis, bool limitLength) +{ + for (int i = 0; i < (int)evalStr.length(); i++) + { + char c = evalStr[i]; + char nextC = 0; + if (i < (int)evalStr.length() - 1) + nextC = evalStr[i + 1]; + if ((c == '{') && (nextC != '{')) + { + // Evaluate + + int endIdx = i; + for (; endIdx < (int)evalStr.length(); endIdx++) + { + //TODO: Do better parsing - this paren could be inside a string, for example + if (evalStr[endIdx] == '}') + break; + } + + CeFormatInfo displayStrFormatInfo = formatInfo; + displayStrFormatInfo.mTotalSummaryLength = formatInfo.mTotalSummaryLength + (int)displayString.length(); + displayStrFormatInfo.mHidePointers = false; + + if ((limitLength) && (displayStrFormatInfo.mTotalSummaryLength > 255)) + { + displayString += "..."; + } + else + { + String evalString = evalStr.Substring(i + 1, endIdx - i - 1); + String errors; + BfTypedValue evalResult = EvaluateInContext(useTypedValue, evalString, &displayStrFormatInfo, NULL, &errors); + if (evalResult) + { + if (displayStrFormatInfo.mNoEdit) + formatInfo.mNoEdit = true; + + String result = TypedValueToString(evalResult, evalString, displayStrFormatInfo, NULL); + + if ((formatInfo.mRawString) && (limitLength)) + { + displayString = result; + return; + } + + int crPos = (int)result.IndexOf('\n'); + if (crPos != -1) + displayString += result.Substring(0, crPos); + else + displayString += result; + } + else if (debugVis != NULL) + { + displayString += ""; + DbgVisFailed(debugVis, evalString, errors); + } + else + { + displayString += ""; + } + } + + i = endIdx; + continue; + } + else if ((c == '{') && (nextC == '{')) + { + // Skip next paren + i++; + } + else if ((c == '}') && (nextC == '}')) + { + // Skip next paren + i++; + } + + displayString += c; + } +} + +String CeDebugger::TypedValueToString(const BfTypedValue& typedValue, const StringImpl& expr, CeFormatInfo& formatInfo, bool fullPrecision) +{ + auto module = mCeMachine->mCeModule; + + String retVal; + if (typedValue.IsNoValueType()) + { + retVal += "\n"; + retVal += module->TypeToString(typedValue.mType); + retVal += "\n"; + retVal += GetMemberList(typedValue.mType, 0, 0, true); + return retVal; + } + + auto constant = module->mBfIRBuilder->GetConstant(typedValue.mValue); + auto ceContext = mCeMachine->mCurContext; + if (constant == NULL) + { + return "!Invalid expression"; + } + + bool didAlloc = false; + addr_ce addr = 0; + + defer( + { + if (didAlloc) + mCurDbgState->mCeContext->CeFree(addr); + } + ); + + if (constant->mConstType == BfConstType_AggCE) + { + auto aggCE = (BfConstantAggCE*)constant; + addr = aggCE->mCEAddr; + } + else if ((typedValue.IsAddr()) || (typedValue.mType->IsObjectOrInterface()) || (typedValue.mType->IsPointer())) + { + CeTypedValue typedVal = GetAddr(constant); + addr = typedVal.mAddr; + if (!typedVal) + { + return "!Invalid addr type"; + } + } + else + { + int allocSize = typedValue.mType->mSize; + auto typeInst = typedValue.mType->ToTypeInstance(); + if (typeInst != NULL) + allocSize = typeInst->mInstSize; + if (allocSize < 0) + return "!Invalid size"; + + addr = (addr_ce)(mCurDbgState->mCeContext->CeMalloc(allocSize) - mCurDbgState->mCeContext->mMemory.mVals); + didAlloc = true; + + if (!mCurDbgState->mCeContext->WriteConstant(mCeMachine->mCeModule, addr, constant, typedValue.mType)) + { + return StrFormat("!Failed to encode value"); + } + } + + DwDisplayInfo* displayInfo = GetDisplayInfo(formatInfo.mReferenceId); + + char str[32]; + String result; + auto memStart = mCurDbgState->mCeContext->mMemory.mVals; + + int checkMemSize = typedValue.mType->mSize; + if (typedValue.mType->IsPointer()) + checkMemSize = typedValue.mType->GetUnderlyingType()->mSize; + + uint8* data = ceContext->GetMemoryPtr(addr, checkMemSize); + if ((addr != 0) && (data == NULL)) + return "!Invalid address"; + + addr_ce dataAddr = addr; + if ((typedValue.IsAddr()) && (typedValue.mType->IsObjectOrInterface())) + dataAddr = *(addr_ce*)data; + + if (formatInfo.mRawString) + { + //if ((dwValueType->mTypeCode != DbgType_Struct) && (dwValueType->mTypeCode != DbgType_Class) && (dwValueType->mTypeCode != DbgType_Ptr) && (dwValueType->mTypeCode != DbgType_SizedArray)) + if ((!typedValue.mType->IsPointer()) && (!typedValue.mType->IsObjectOrStruct()) && (!typedValue.mType->IsStruct()) && (!typedValue.mType->IsSizedArray())) + return ""; + } + + auto _ShowArraySummary = [&](String& retVal, addr_ce ptrVal, int64 arraySize, BfType* innerType) + { + auto ptrType = module->CreatePointerType(innerType); + + String displayString; + displayString += "{"; + for (int idx = 0; idx < arraySize; idx++) + { + if (formatInfo.mTotalSummaryLength + retVal.length() + displayString.length() > 255) + { + displayString += "..."; + break; + } + + if ((idx != 0) && (!displayString.EndsWith('{'))) + displayString += ", "; + + CeFormatInfo displayStrFormatInfo = formatInfo; + displayStrFormatInfo.mExpandItemDepth = 1; + displayStrFormatInfo.mTotalSummaryLength = formatInfo.mTotalSummaryLength + (int)retVal.length() + (int)displayString.length(); + displayStrFormatInfo.mHidePointers = false; + displayStrFormatInfo.mArrayLength = -1; + + // Why did we have this "na" on here? It made "void*[3]" type things show up as "{,,}" + //String evalStr = "((" + innerType->ToStringRaw(language) + "*)" + EncodeDataPtr(ptrVal, true) + StrFormat(")[%d], na", idx); + + String evalStr = StrFormat("((comptype(%d))(void*)", ptrType->mTypeId) + EncodeDataPtr(ptrVal, true) + StrFormat(")[%lld]", idx); + BfTypedValue evalResult = EvaluateInContext(typedValue, evalStr, &displayStrFormatInfo); + String result; + if (evalResult) + { + result = TypedValueToString(evalResult, evalStr, displayStrFormatInfo, NULL); + int crPos = (int)result.IndexOf('\n'); + if (crPos != -1) + result.RemoveToEnd(crPos); + } + else + result = "???"; + + displayString += result; + } + displayString += "}"; + retVal += displayString; + }; + + if (formatInfo.mArrayLength != -1) + { + if (formatInfo.mRawString) + return ""; + + if (typedValue.mType->IsPointer()) + { + auto elementType = typedValue.mType->GetUnderlyingType(); + + String retVal; + addr_ce ptrVal = addr; + if (!formatInfo.mHidePointers) + { + retVal = EncodeDataPtr(ptrVal, true) + " "; + retVal += module->TypeToString(elementType); + retVal += StrFormat("[%lld] ", (int64)formatInfo.mArrayLength); + } + + _ShowArraySummary(retVal, ptrVal, formatInfo.mArrayLength, elementType); + + String idxStr = "[{0}]"; + + retVal += "\n" + module->TypeToString(typedValue.mType); + + String evalStr = StrFormat("((comptype(%d))(void*)", typedValue.mType->mTypeId) + EncodeDataPtr(ptrVal, true) + ")[{0}]"; + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, (int)BF_MAX(formatInfo.mArrayLength, 0), 10000) + + "\t" + idxStr + "\t" + evalStr; + return retVal; + } + else + { + CeFormatInfo newFormatInfo = formatInfo; + newFormatInfo.mArrayLength = -1; + + String retVal = TypedValueToString(typedValue, expr, newFormatInfo); + + int crPos = (int)retVal.IndexOf('\n'); + if (crPos != -1) + retVal = "!Array length flag not valid with this type" + retVal.Substring(crPos); + return retVal; + } + } + + if (typedValue.mType->IsPrimitiveType()) + { + auto primType = (BfPrimitiveType*)typedValue.mType; + + BfTypeCode typeCode = primType->mTypeDef->mTypeCode; + if (typeCode == BfTypeCode_IntPtr) + typeCode = (primType->mSize == 8) ? BfTypeCode_Int64 : BfTypeCode_Int32; + if (typeCode == BfTypeCode_UIntPtr) + typeCode = (primType->mSize == 8) ? BfTypeCode_UInt64 : BfTypeCode_UInt32; + + switch (typeCode) + { + case BfTypeCode_Boolean: + { + auto val = *(uint8*)(data); + if (val == 0) + return "false\nbool"; + else if (val == 1) + return "true\nbool"; + else + return StrFormat("true (%d)\nbool", val); + } + break; + case BfTypeCode_Char8: + { + auto val = *(uint8*)(data); + if (val != 0) + { + char str[2] = { (char)val }; + result = SlashString(str, formatInfo.mDisplayType == DwDisplayType_Utf8, true); + + if (!IsNormalChar(val)) + result = StrFormat("'%s' (0x%02X)\n", result.c_str(), val); + else + result = StrFormat("'%s'\n", result.c_str()); + } + else + result = "'\\0'\n"; + return result + "char"; + } + break; + case BfTypeCode_Char16: + { + auto val = *(uint16*)(data); + if (val != 0) + { + u8_toutf8(str, 8, val); + result = SlashString(str, true, true); + if (!IsNormalChar(val)) + result = StrFormat("'%s' (0x%02X)\n", result.c_str(), val); + else + result = StrFormat("'%s'\n", result.c_str()); + } + else + result = "'\\0'\n"; + return result + "char16"; + } + break; + case BfTypeCode_Char32: + { + auto val = *(uint32*)(data); + if (val != 0) + { + u8_toutf8(str, 8, val); + result = SlashString(str, true, true); + if (!IsNormalChar(val)) + result = StrFormat("'%s' (0x%02X)\n", result.c_str(), val); + else + result = StrFormat("'%s'\n", result.c_str()); + } + else + result = "'\\0'\n"; + return result + "char32"; + } + break; + case BfTypeCode_Int8: + return IntTypeToString(*(int8*)(data), "int8", displayInfo, formatInfo); + case BfTypeCode_UInt8: + return IntTypeToString(*(uint8*)(data), "uint8", displayInfo, formatInfo); + case BfTypeCode_Int16: + return IntTypeToString(*(int16*)(data), "int16", displayInfo, formatInfo); + case BfTypeCode_UInt16: + return IntTypeToString(*(uint16*)(data), "uint16", displayInfo, formatInfo); + case BfTypeCode_Int32: + return IntTypeToString(*(int32*)(data), "int32", displayInfo, formatInfo); + case BfTypeCode_UInt32: + return IntTypeToString(*(uint32*)(data), "uint32", displayInfo, formatInfo); + case BfTypeCode_Int64: + return IntTypeToString(*(int64*)(data), "int64", displayInfo, formatInfo); + case BfTypeCode_UInt64: + return IntTypeToString(*(uint64*)(data), "uint64", displayInfo, formatInfo); + case BfTypeCode_Float: + { + DwFloatDisplayType floatDisplayType = displayInfo->mFloatDisplayType; + if (floatDisplayType == DwFloatDisplayType_Default) + floatDisplayType = DwFloatDisplayType_Minimal; + if (floatDisplayType == DwFloatDisplayType_Minimal) + ExactMinimalFloatToStr(*(float*)data, str); + else if (floatDisplayType == DwFloatDisplayType_Full) + sprintf(str, "%1.9g", *(float*)data); + else if (floatDisplayType == DwFloatDisplayType_HexUpper) + sprintf(str, "0x%04X", *(uint32*)data); + else //if (floatDisplayType == DwFloatDisplayType_HexLower) + sprintf(str, "0x%04x", *(uint32*)data); + return StrFormat("%s\n%s", str, "float"); + } + case BfTypeCode_Double: + { + DwFloatDisplayType floatDisplayType = displayInfo->mFloatDisplayType; + if (floatDisplayType == DwFloatDisplayType_Default) + floatDisplayType = DwFloatDisplayType_Minimal; + if (floatDisplayType == DwFloatDisplayType_Minimal) + ExactMinimalDoubleToStr(*(double*)data, str); + else if (floatDisplayType == DwFloatDisplayType_Full) + sprintf(str, "%1.17g", *(double*)data); + else if (floatDisplayType == DwFloatDisplayType_HexUpper) + sprintf(str, "0x%08llX", *(uint64*)data); + else //if (floatDisplayType == DwFloatDisplayType_HexLower) + sprintf(str, "0x%08llx", *(uint64*)data); + return StrFormat("%s\n%s", str, "double"); + } + } + } + + if (typedValue.mType->IsPointer()) + { + //ceContext-> + + addr_ce ptrVal = addr; + + String retVal; + BfType* innerType = typedValue.mType->GetUnderlyingType(); + if (innerType == NULL) + return EncodeDataPtr((uint32)ptrVal, true) + "\nvoid*"; + + bool isChar = false; + + if (innerType->IsChar()) + isChar = true; + + if ((isChar) && (formatInfo.mArrayLength == -1)) + { + auto primType = (BfPrimitiveType*)innerType; + + if (!formatInfo.mHidePointers) + retVal = EncodeDataPtr(ptrVal, true); + + int strLen = (int)formatInfo.mOverrideCount; +// if (typedValue.mIsLiteral) +// { +// if (strLen == -1) +// strLen = 0x7FFFFFFF; +// if (typedValue.mDataLen > 0) +// strLen = BF_MIN(strLen, typedValue.mDataLen); +// else +// strLen = BF_MIN(strLen, strlen(typedValue.mCharPtr)); +// } + + SetAndRestoreValue prevOverrideLen(formatInfo.mOverrideCount, strLen); + String strResult = ReadString(primType->mTypeDef->mTypeCode, ptrVal, strLen, formatInfo); + if (formatInfo.mRawString) + return strResult; + if (!strResult.IsEmpty()) + { + if (!retVal.IsEmpty()) + retVal += " "; + retVal += strResult; + } + retVal += "\n" + module->TypeToString(typedValue.mType); + return retVal; + } +// else if ((unmodInnerType != NULL) && +// ((unmodInnerType->mTypeCode == DbgType_Class) || (unmodInnerType->mTypeCode == DbgType_Struct) || (unmodInnerType->mTypeCode == DbgType_Union))) +// { +// isCompositeType = true; +// } +// else if ((unmodInnerType != NULL) && (unmodInnerType->mTypeCode == DbgType_SizedArray)) +// { +// isSizedArray = true; +// } +// else if (unmodInnerType->mTypeCode == DbgType_Subroutine) +// { +// if (formatInfo.mRawString) +// return ""; +// addr_ce funcPtr = (addr_ce)typedValue.mPtr; +// String retVal; +// if ((!typedValue.mIsLiteral) && (!formatInfo.mHidePointers)) +// retVal = EncodeDataPtr(funcPtr, true); +// +// String symbolName; +// addr_ce offset; +// DbgModule* dwarf; +// static String demangledName; +// auto subProgram = mDebugTarget->FindSubProgram(funcPtr); +// if (subProgram != NULL) +// { +// demangledName = subProgram->ToString(); +// } +// else if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf)) +// { +// demangledName = BfDemangler::Demangle(symbolName, language); +// +// if (offset != 0) +// demangledName += StrFormat("+%d", offset); +// } +// else +// { +// auto dbgModule = mDebugTarget->FindDbgModuleForAddress(funcPtr); +// if (dbgModule != NULL) +// demangledName += dbgModule->GetLinkedModule()->mDisplayName + "!"; +// demangledName += StrFormat("0x%@", funcPtr); +// } +// +// retVal += " {"; +// retVal += demangledName; +// retVal += "}"; +// retVal += "\n" + origValueType->ToString(language); +// +// return retVal; +// } +// else if (unmodInnerType->mTypeCode == DbgType_Void) +// { +// if (formatInfo.mRawString) +// return ""; +// addr_ce ptr = (addr_ce)typedValue.mPtr; +// String symbolName; +// addr_ce offset; +// DbgModule* dwarf; +// String demangledName; +// +// retVal += demangledName = StrFormat("0x%@", ptr); +// +// if (mDebugTarget->FindSymbolAt(ptr, &symbolName, &offset, &dwarf)) +// { +// if (offset == 0) +// { +// retVal += " {"; +// retVal += BfDemangler::Demangle(symbolName, language); +// retVal += "}"; +// } +// } +// +// retVal += "\n" + origValueType->ToString(language); +// +// return retVal; +// } +// else + { + if (formatInfo.mRawString) + return ""; + + String retVal; + if (!formatInfo.mHidePointers) + retVal = EncodeDataPtr((uint32)ptrVal, true); + + if (ptrVal != 0) + { + BfTypedValue innerTypedVal = BfTypedValue(module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(innerType), (addr_ce)ptrVal), innerType, true); + + innerTypedVal.mType = innerType; + + if (innerTypedVal) + { + CeFormatInfo defaultFormatInfo; + defaultFormatInfo.mTotalSummaryLength = formatInfo.mTotalSummaryLength + 2; // Take into accout the necessary {}'s + defaultFormatInfo.mExpandItemDepth++; + defaultFormatInfo.mCallStackIdx = formatInfo.mCallStackIdx; + String innerStr = TypedValueToString(innerTypedVal, "", defaultFormatInfo); + int crIdx = (int)innerStr.IndexOf('\n'); + if (crIdx != -1) + { + String innerDataStr = innerStr.Substring(0, crIdx); + if (!innerDataStr.empty()) + { + if (!retVal.empty()) + retVal += " "; + retVal += "{" + innerDataStr + "}"; + } + } + else + { + retVal += " { ??? }"; + } + } + } + + retVal += "\n" + module->TypeToString(typedValue.mType); + module->PopulateType(innerType); + + if (ptrVal != 0) + { + //String ptrDataStr = StrFormat("(%s)", dwValueType->ToStringRaw(language).c_str()) + EncodeDataPtr(typedValue.mPtr, true); + retVal += "\n*\t"; + // Why did we have this? It messed up a pointer to sized array + /*if (language == DbgLanguage_Beef) + retVal += "this"; + else*/ + retVal += "this"; + + if (!formatInfo.mReferenceId.empty()) + retVal += ", refid=" + MaybeQuoteFormatInfoParam(formatInfo.mReferenceId); + + retVal += StrFormat(", this=%d@0x%X", innerType->mTypeId, ptrVal); + } + + retVal += "\n:editVal\t" + EncodeDataPtr((uint32)addr, true); + + return retVal; + } + } + + if (typedValue.mType->IsSizedArray()) + { + auto arrayType = (BfSizedArrayType*)typedValue.mType; + auto innerType = arrayType->mElementType; + + String retVal; + addr_ce ptrVal = addr; + + intptr arraySize = arrayType->mElementCount; + intptr innerSize = innerType->GetStride(); + + String idxStr = "[{0}]"; + + if (innerType->IsChar()) + { + auto primType = (BfPrimitiveType*)innerType; + String strVal = ReadString(primType->mTypeDef->mTypeCode, ptrVal, arraySize, formatInfo); + if (formatInfo.mRawString) + return strVal; + retVal += strVal; + } + else + { + if (formatInfo.mRawString) + return ""; + + _ShowArraySummary(retVal, ptrVal, arraySize, innerType); + } + + retVal += "\n" + module->TypeToString(typedValue.mType); + + String referenceId = module->TypeToString(typedValue.mType); + String evalStr; + + // Why did we have the "na"? Do we not want to show addresses for all members? + + auto ptrType = module->CreatePointerType(innerType); + + evalStr = StrFormat("((comptype(%d))(void*)", ptrType->mTypeId) + EncodeDataPtr(ptrVal, true) + ")[{0}], refid=" + MaybeQuoteFormatInfoParam(referenceId + ".[]"); + if (typedValue.IsReadOnly()) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, (int)BF_MAX(arraySize, 0), 10000) + + "\t" + idxStr + "\t" + evalStr; + return retVal; + } + + if (typedValue.mType->IsEnum()) + { + String retVal; + int64 bitsLeft = ValueToInt(typedValue); + int valueCount = 0; + + String editVal; + + auto typeInst = typedValue.mType->ToTypeInstance(); + auto dbgTypeInfo = GetDbgTypeInfo(typedValue.mType->mTypeId); + + while ((dbgTypeInfo != NULL) && ((bitsLeft != 0) || (valueCount == 0))) + { + CeDbgTypeInfo::ConstIntEntry* bestMatch = NULL; + + for (auto& constIntEntry : dbgTypeInfo->mConstIntEntries) + { + if (constIntEntry.mVal == bitsLeft) + { + bestMatch = &constIntEntry; + break; + } + } + + if (bestMatch == NULL) + { + for (auto& constIntEntry : dbgTypeInfo->mConstIntEntries) + { + if ((constIntEntry.mVal != 0) && + ((constIntEntry.mVal & bitsLeft) == constIntEntry.mVal)) + { + bestMatch = &constIntEntry; + break; + } + } + } + + if (bestMatch == NULL) + break; + + if (valueCount > 0) + { + retVal += " | "; + } + + auto bestFieldInstance = &typeInst->mFieldInstances[bestMatch->mFieldIdx]; + + retVal += "."; + retVal += bestFieldInstance->GetFieldDef()->mName; + + valueCount++; + bitsLeft &= ~bestMatch->mVal; + } + + if ((valueCount == 0) || (bitsLeft != 0)) + { + if (valueCount > 0) + retVal += " | "; + retVal += StrFormat("%lld", bitsLeft); + } + + retVal += "\n" + module->TypeToString(typedValue.mType); + retVal += "\n:canEdit"; + + return retVal; + } + + if (typedValue.mType->IsTypedPrimitive()) + { + auto innerType = typedValue.mType->GetUnderlyingType(); + + BfTypedValue innerTypedVal = typedValue; + innerTypedVal.mType = innerType; + + auto innerReturn = TypedValueToString(innerTypedVal, expr, formatInfo, fullPrecision); + if (innerReturn.StartsWith("!")) + return innerReturn; + + int crPos = (int)innerReturn.IndexOf('\n'); + if (crPos == -1) + return innerReturn; + + retVal += "{ "; + retVal += innerReturn.Substring(0, crPos); + retVal += " }"; + retVal += "\n" + module->TypeToString(typedValue.mType); + return retVal; + } + + bool isCompositeType = typedValue.mType->IsStruct() || typedValue.mType->IsObject(); + + if (isCompositeType) + { + BfTypeInstance* displayType = typedValue.mType->ToTypeInstance(); + + bool isMemoryValid = true; + + if ((dataAddr == 0) && (addr != 0)) + dataAddr = *(addr_ce*)data; + + if (((typedValue.mType->IsObjectOrInterface()) && + (!formatInfo.mHidePointers) || (dataAddr == 0))) + { + retVal = EncodeDataPtr((uint32)dataAddr, true); + retVal += " "; + + if (!ceContext->CheckMemory(dataAddr, displayType->mInstSize)) + isMemoryValid = false; + } + + bool isBadSrc = false; + bool isNull = dataAddr == 0; + bool hadCustomDisplayString = false; + + BfTypeInstance* actualType = displayType; + bool useActualRawType = false; + + bool isTuple = typedValue.mType->IsTuple(); + + String ptrDataStr; + + if (!formatInfo.mIgnoreDerivedClassInfo) + { + if (actualType->IsObject()) + { + if (dataAddr != 0) + { + uint8* dataPtr = ceContext->GetMemoryPtr(dataAddr, 4); + if (dataPtr == 0) + return "!Invalid object address"; + int actualTypeid = *(int32*)dataPtr; + auto checkType = mCompiler->mContext->FindTypeById(actualTypeid); + if (checkType != NULL) + actualType = checkType->ToTypeInstance(); + } + } + } + + DebugVisualizerEntry* debugVis = NULL; + Array dbgVisWildcardCaptures; + + if ((!formatInfo.mNoVisualizers) && (!isNull) && (!isBadSrc)) + { + debugVis = FindVisualizerForType(displayType, &dbgVisWildcardCaptures); + } + + bool wantsCustomExpandedItems = false; + String displayString; + if (debugVis != NULL) + { + auto& displayStringList = formatInfo.mRawString ? debugVis->mStringViews : debugVis->mDisplayStrings; + + for (auto displayEntry : displayStringList) + { + if (!displayEntry->mCondition.empty()) + { + if (!EvalCondition(debugVis, typedValue, formatInfo, displayEntry->mCondition, dbgVisWildcardCaptures, displayString)) + continue; + } + + hadCustomDisplayString = true; + String displayStr = mDebugManager->mDebugVisualizers->DoStringReplace(displayEntry->mString, dbgVisWildcardCaptures); + if (displayString.length() > 0) + displayString += " "; + ProcessEvalString(typedValue, displayStr, displayString, formatInfo, debugVis, true); + if (formatInfo.mRawString) + return displayString; + + break; + } + + if ((!debugVis->mExpandItems.empty()) || (debugVis->mCollectionType != DebugVisualizerEntry::CollectionType_None)) + { + wantsCustomExpandedItems = true; + } + } + + if (formatInfo.mRawString) + return ""; + + if ((!isNull) && (!formatInfo.mNoVisualizers) && (!hadCustomDisplayString)) + { + // Create our own custom display + + String firstRet; + String bigRet = isTuple ? "(" : "{ "; + + int memberIdx = 0; + BfType* summaryType = typedValue.mType; + bool summaryDone = false; + bool truncatedMemberList = false; + + BfTypedValue summaryTypedValue = typedValue; + String summaryDataStr = ptrDataStr; + String splatStr; + if (dataAddr == -1) + splatStr = expr; + + while ((summaryType != NULL) && (isMemoryValid)) + { + if ((summaryType->IsTypedPrimitive()) + //&& ((summaryType->mBaseTypes.IsEmpty()) || (!summaryType->mBaseTypes.front()->mBaseType->IsTypedPrimitive()))) + ) + { + if (formatInfo.mTotalSummaryLength + (int)displayString.length() > 255) + { + truncatedMemberList = true; + summaryDone = true; + bigRet += "..."; + } + else + { + CeFormatInfo displayStrFormatInfo = formatInfo; + displayStrFormatInfo.mExpandItemDepth = 1; + displayStrFormatInfo.mTotalSummaryLength += (int)displayString.length(); + displayStrFormatInfo.mHidePointers = false; + + BfType* primType = summaryType->GetUnderlyingType(); + String result; + + if (primType->IsInteger()) + formatInfo.mTypeKindFlags = (DbgTypeKindFlags)(formatInfo.mTypeKindFlags | DbgTypeKindFlag_Int); + + if ((dataAddr != 0) && (dataAddr != -1)) + { + //String evalString = "(" + primType->ToString() + ")" + ptrDataStr; +// BfTypedValue evalResult = EvaluateInContext(dbgCompileUnit, origTypedValue, evalString, &displayStrFormatInfo); +// if (evalResult) +// result = TypedValueToString(evalResult, evalString, displayStrFormatInfo, NULL); + } + else + { +// BfTypedValue evalResult = origTypedValue; +// evalResult.mType = primType; +// String evalString = "(" + primType->ToString() + ")" + expr; +// result = TypedValueToString(evalResult, evalString, displayStrFormatInfo, NULL); + } + + if (formatInfo.mRawString) + return result; + + int crPos = (int)result.IndexOf('\n'); + if (crPos != -1) + result.RemoveToEnd(crPos); + + if (memberIdx == 0) + firstRet = result; + + bigRet += result; + memberIdx++; + } + } + + auto summaryTypeInst = summaryType->ToTypeInstance(); + if (summaryTypeInst == NULL) + break; + + module->PopulateType(summaryTypeInst); + for (auto& fieldInst : summaryTypeInst->mFieldInstances) + { + auto fieldDef = fieldInst.GetFieldDef(); + if (!fieldDef->mIsStatic) + { + if (formatInfo.mTotalSummaryLength + retVal.length() + bigRet.length() > 255) + { + truncatedMemberList = true; + summaryDone = true; + bigRet += "..."; + break; + } + + //if (fieldDef->mName != NULL) + { +// if (member->mName[0] == '$') +// continue; + + if (!isdigit(fieldDef->mName[0])) + { + if (memberIdx != 0) + bigRet += isTuple ? ", " : " "; + + if ((!isTuple) || (fieldDef->mName[0] != '_')) + { + bigRet += String(fieldDef->mName); + bigRet += isTuple ? ":" : "="; + } + } + else + { + if (memberIdx != 0) + bigRet += ", "; + } + + CeFormatInfo displayStrFormatInfo = formatInfo; + displayStrFormatInfo.mExpandItemDepth = 1; + displayStrFormatInfo.mHidePointers = false; + displayStrFormatInfo.mTotalSummaryLength = (int)(formatInfo.mTotalSummaryLength + retVal.length() + bigRet.length()); + +// String evalString; +// if (dataPtr != -1) +// { +// if ((fieldDef->mName[0] >= '0') && (fieldDef->mName[0] <= '9')) +// evalString += "this."; +// evalString += String(member->mName); // +", this=" + summaryDataStr; +// } +// else +// { +// evalString = "("; +// evalString += splatStr; +// evalString += ")."; +// evalString += fieldDef->mName; +// } + String referenceId; + String result; + if (!fieldInst.mResolvedType->IsValuelessType()) + { + auto addrVal = dataAddr + fieldInst.mDataOffset; + + BfTypedValue evalResult; + if (fieldInst.mResolvedType->IsObjectOrInterface()) + { + auto typeInst = fieldInst.mResolvedType->ToTypeInstance(); + evalResult = BfTypedValue(module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapTypeInst(typeInst), (addr_ce)addrVal), typeInst, true); + } + else + { + evalResult = BfTypedValue(module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(fieldInst.mResolvedType), (addr_ce)addrVal), fieldInst.mResolvedType, true); + } + + //BfTypedValue evalResult = EvaluateInContext(dbgCompileUnit, summaryTypedValue, evalString, &displayStrFormatInfo, &referenceId); + if (evalResult) + { + displayStrFormatInfo.mReferenceId = referenceId; + result = TypedValueToString(evalResult, "", displayStrFormatInfo, NULL); + int crPos = (int)result.IndexOf('\n'); + if (crPos != -1) + result.RemoveToEnd(crPos); + } + else + result = "???"; + } + + if (fieldInst.mResolvedType->IsInteger()) + formatInfo.mTypeKindFlags = (DbgTypeKindFlags)(formatInfo.mTypeKindFlags | DbgTypeKindFlag_Int); + + if (formatInfo.mRawString) + return result; + + if (memberIdx == 0) + firstRet = result; + + bigRet += result; + //formatInfo.mEmbeddedDisplayCount = displayStrFormatInfo.mEmbeddedDisplayCount; + memberIdx++; + } + } + } + + if (truncatedMemberList) + break; + + // Find first base class with members + BfType* nextSummaryType = summaryTypeInst->mBaseType; + summaryType = nextSummaryType; + + if ((summaryType == NULL) || (summaryType == module->mContext->mBfObjectType)) + break; + + // If we don't have many members then find a base class with some members to show + if ((memberIdx != 0) && (displayString.length() >= 255)) + { + truncatedMemberList = true; + bigRet += "..."; + break; + } + } + + bigRet += isTuple ? ")" : " }"; + + if (displayString.length() > 0) + displayString += " "; + if ((memberIdx == 1) && (!truncatedMemberList) && (firstRet.IndexOf('{') == -1) && (!isTuple)) + displayString += "{ " + firstRet + " }"; + else + displayString += bigRet; + } + + retVal += displayString; + retVal += "\n" + module->TypeToString(displayType); + + if ((actualType != NULL) && (actualType != displayType)) + { + String actualTypeName = module->TypeToString(actualType); + retVal += StrFormat(" {%s}\n[%s]\tthis,this=%d@0x%X", actualTypeName.c_str(), actualTypeName.c_str(), actualType->mTypeId, addr); + } + + if (formatInfo.mNoMembers) + { + // + } + else if (wantsCustomExpandedItems) + { + HandleCustomExpandedItems(retVal, debugVis, typedValue, addr, dataAddr, dbgVisWildcardCaptures, formatInfo); + } + else if ((!isNull) && (!isBadSrc)) + { + retVal += "\n" + GetMemberList(displayType, addr, dataAddr, false); + } + + if (typedValue.mType->IsObjectOrInterface()) + { + retVal += "\n:editVal\t" + EncodeDataPtr((uint32)dataAddr, true); + } + return retVal; + } + + return "!unknown type"; +} + +void CeDebugger::HandleCustomExpandedItems(String& retVal, DebugVisualizerEntry* debugVis, BfTypedValue typedValue, addr_ce addr, addr_ce addrInst, Array& dbgVisWildcardCaptures, CeFormatInfo& formatInfo) +{ + auto debugVisualizers = mDebugManager->mDebugVisualizers; + auto ceModule = mCeMachine->mCeModule; + + if (formatInfo.mExpandItemDepth > 10) // Avoid crashing on circular ExpandItems + return; + + bool isReadOnly = false; +// if (useTypedValue.mIsReadOnly) +// isReadOnly = true; + + String ptrUseDataStr = StrFormat("%d@0x%X", typedValue.mType->mTypeId, addrInst); + + for (auto entry : debugVis->mExpandItems) + { + if (!entry->mCondition.empty()) + { + String error; + if (!EvalCondition(debugVis, typedValue, formatInfo, entry->mCondition, dbgVisWildcardCaptures, error)) + { + if (!error.empty()) + retVal += "\n" + entry->mName + "\t@!@!"; + continue; + } + } + String replacedStr = debugVisualizers->DoStringReplace(entry->mValue, dbgVisWildcardCaptures); + retVal += "\n" + entry->mName + "\t" + replacedStr + ", this=" + ptrUseDataStr; + } + + String referenceId = ceModule->TypeToString(typedValue.mType); + + if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_ExpandedItem) + { + BfTypedValue itemValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures), &formatInfo); + if (itemValue) + { + CeFormatInfo itemFormatInfo = formatInfo; + itemFormatInfo.mExpandItemDepth++; + String itemRetVal = TypedValueToString(itemValue, "", itemFormatInfo, NULL); + + int crIdx = (int)itemRetVal.IndexOf('\n'); + if (crIdx != -1) + { + crIdx = (int)itemRetVal.IndexOf('\n', crIdx + 1); + if (crIdx != -1) + retVal += itemRetVal.Substring(crIdx); + } + } + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_Array) + { + BfTypedValue sizeValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures), &formatInfo); + Array lowerDimSizes; + for (auto lowerDim : debugVis->mLowerDimSizes) + { + BfTypedValue lowerDimValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(lowerDim, dbgVisWildcardCaptures), &formatInfo); + int dimSize = 0; + if ((lowerDimValue) && (lowerDimValue.mType->IsInteger())) + dimSize = (int)ValueToInt(lowerDimValue); + dimSize = BF_MAX(dimSize, 1); + lowerDimSizes.push_back(dimSize); + } + + if ((sizeValue) && (sizeValue.mType->IsInteger()) && (ValueToInt(sizeValue) > 0)) + { + if (!debugVis->mCondition.IsEmpty()) + { + int size = (int)ValueToInt(sizeValue); + BfTypedValue headPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures), &formatInfo); + + BfTypedValue curNode = headPointer; + Array parentList; + String continuationData; + + int totalSize = 2; + auto valueType = headPointer.mType; + String addrs = GetArrayItems(debugVis, valueType, headPointer, totalSize, &continuationData); + String firstAddr; + String secondAddr; + bool hasSecondAddr = valueType == NULL; + if (addrs.length() > 0) + { + const char* addrsPtr = addrs.c_str(); + firstAddr = addrs.Substring(0, sizeof(addr_ce) * 2); + if (hasSecondAddr) + secondAddr = addrs.Substring(sizeof(addr_ce) * 2, sizeof(addr_ce) * 2); + } + + String evalStr; + if (valueType != NULL) + { + auto ptrType = valueType; + if (!valueType->IsPointer()) + ptrType = ceModule->CreatePointerType(valueType); + evalStr = StrFormat("(comptype(%d)", ptrType->mTypeId); + evalStr += ")(void*)0x{1}"; + } + else + { + evalStr += "({1})(void*)0x{2}"; + } + if (!debugVis->mShowElementAddrs) + evalStr.Insert(0, "*"); + + if (addrs.length() > 0) + { + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, BF_MAX(size, 0), 10000) + + "\t[{0}]\t" + evalStr + "\t" + firstAddr; + + if (hasSecondAddr) + retVal += "\t" + secondAddr; + + if (size != 0) + { + retVal += "\n:addrs\t" + addrs; + if (valueType == NULL) + retVal += "\n:addrsEntrySize\t2"; + if (continuationData.length() > 0) + retVal += "\n:continuation\t" + continuationData; + } + } + } + else if (lowerDimSizes.size() == 1) + { + int dimSize1 = lowerDimSizes[0]; + + String evalStr = "(" + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + + StrFormat(" + {0} * %d), arraysize=%d, na, this=", dimSize1, dimSize1) + ptrUseDataStr; + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, ValueToInt(sizeValue) / dimSize1, 50000) + + "\t[{0}]\t" + evalStr; + } + else if (lowerDimSizes.size() == 2) + { + int dimSize1 = lowerDimSizes[0]; + int dimSize2 = lowerDimSizes[1]; + + BfTypedValue headPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures), &formatInfo); + if ((headPointer.mType != NULL) && (headPointer.mType->IsPointer())) + { + String evalStr = StrFormat("((%s[%d]*)", ceModule->TypeToString(headPointer.mType->GetUnderlyingType()).c_str(), dimSize2) + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + + StrFormat(" + {0} * %d), arraysize=%d, na, this=", dimSize1, dimSize1) + ptrUseDataStr; + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, ValueToInt(sizeValue) / dimSize1 / dimSize2, 50000) + + "\t[{0}]\t" + evalStr; + } + } + else if (lowerDimSizes.size() == 3) + { + int dimSize1 = lowerDimSizes[0]; + int dimSize2 = lowerDimSizes[1]; + int dimSize3 = lowerDimSizes[2]; + + BfTypedValue headPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures), &formatInfo); + if ((headPointer.mType != NULL) && (headPointer.mType->IsPointer())) + { + String evalStr = StrFormat("((%s[%d][%d]*)", ceModule->TypeToString(headPointer.mType->GetUnderlyingType()).c_str(), dimSize2, dimSize3) + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + + StrFormat(" + {0} * %d), arraysize=%d, na, this=", dimSize1, dimSize1) + ptrUseDataStr; + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, ValueToInt(sizeValue) / dimSize1 / dimSize2 / dimSize3, 50000) + + "\t[{0}]\t" + evalStr; + } + } + else + { + String evalStr = "*(" + debugVisualizers->DoStringReplace(debugVis->mValuePointer, dbgVisWildcardCaptures) + " + {0}), this=" + ptrUseDataStr; + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, ValueToInt(sizeValue), 50000) + + "\t[{0}]\t" + evalStr; + } + } + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_IndexItems) + { + BfTypedValue sizeValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures), &formatInfo); + + if ((sizeValue) && (sizeValue.mType->IsInteger()) && (ValueToInt(sizeValue) > 0)) + { + String evalStr = debugVis->mValuePointer + ", this=" + ptrUseDataStr; + evalStr.Replace("$i", "{0}"); + + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, ValueToInt(sizeValue), 50000) + + "\t[{0}]\t" + evalStr; + } + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_LinkedList) + { + BfType* valueType = NULL; + if (!debugVis->mValueType.empty()) + { + valueType = FindType(debugVisualizers->DoStringReplace(debugVis->mValueType, dbgVisWildcardCaptures)); + } + + BfTypedValue headPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mHeadPointer, dbgVisWildcardCaptures), &formatInfo); + if (headPointer) + { + BfTypedValue endPointer; + if (!debugVis->mEndPointer.empty()) + endPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mEndPointer, dbgVisWildcardCaptures), &formatInfo); + BfTypedValue nextPointer = EvaluateInContext(headPointer, debugVisualizers->DoStringReplace(debugVis->mNextPointer, dbgVisWildcardCaptures), &formatInfo); + + int size = -1; + if (!debugVis->mSize.empty()) + { + auto sizeValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures), &formatInfo); + if (sizeValue) + size = (int)ValueToInt(sizeValue); + } + + BfTypedValue curNode = headPointer; + Array parentList; + String continuationData; + + int totalSize = 2; + String addrs; //TODO: = GetLinkedListItems(debugVis, endPointer.mPtr, valueType, curNode, totalSize, &continuationData); + String firstAddr; + String secondAddr; + bool hasSecondAddr = valueType == NULL; + if (addrs.length() > 0) + { + const char* addrsPtr = addrs.c_str(); + firstAddr = addrs.Substring(0, sizeof(addr_ce) * 2); + if (hasSecondAddr) + secondAddr = addrs.Substring(sizeof(addr_ce) * 2, sizeof(addr_ce) * 2); + } + + String evalStr; + if (valueType != NULL) + { + auto ptrType = valueType; + if (!valueType->IsPointer()) + ptrType = ceModule->CreatePointerType(valueType); + evalStr = StrFormat("(comptype(%d)", ptrType->mTypeId); + evalStr += ")0x{1}"; + } + else + { + evalStr += "({1})0x{2}"; + } + if (!debugVis->mShowElementAddrs) + evalStr.Insert(0, "*"); + + if (addrs.length() > 0) + { + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, size, 10000) + + "\t[{0}]\t" + evalStr + "\t" + firstAddr; + + if (hasSecondAddr) + retVal += "\t" + secondAddr; + + if (size != 0) + { + retVal += "\n:addrs\t" + addrs; + if (valueType == NULL) + retVal += "\n:addrsEntrySize\t2"; + if (continuationData.length() > 0) + retVal += "\n:continuation\t" + continuationData; + } + } + } + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_TreeItems) + { + BfType* valueType = NULL; + if (!debugVis->mValueType.empty()) + { + valueType = FindType(debugVisualizers->DoStringReplace(debugVis->mValueType, dbgVisWildcardCaptures)); + } + + BfTypedValue sizeValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures), &formatInfo); + BfTypedValue headPointer = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mHeadPointer, dbgVisWildcardCaptures), &formatInfo); + + if ((sizeValue) && (headPointer) && (sizeValue.mType->IsInteger()) && (ValueToInt(sizeValue) > 0)) + { + BfTypedValue curNode = headPointer; + Array parentList; + String continuationData; + + int getItemCount = (int)BF_MIN(ValueToInt(sizeValue), 32LL); + + String addrs; //TODO: = GetTreeItems(dbgCompileUnit, debugVis, parentList, valueType, curNode, getItemCount, &continuationData); + addr_ce firstAddr = 0; + addr_ce secondAddr = 0; + bool hasSecondAddr = valueType == NULL; + if (addrs.length() > 0) + { + const char* addrsPtr = addrs.c_str(); + firstAddr = DecodeTargetDataPtr(addrsPtr); + if (hasSecondAddr) + secondAddr = DecodeTargetDataPtr(addrsPtr); + } + + String evalStr; + if (valueType != NULL) + { + auto ptrType = valueType; + if (!valueType->IsPointer()) + ptrType = ceModule->CreatePointerType(valueType); + evalStr = StrFormat("(comptype(%d)", ptrType->mTypeId); + evalStr += ")0x{1}";; + } + else + { + evalStr += "*(_T_{1}*)0x{2}"; + } + + int size = (int)ValueToInt(sizeValue); + if (addrs.length() == 0) + { + evalStr = ""; // Failed + } + + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, size, 10000) + + "\t[{0}]\t" + evalStr + "\t" + EncodeDataPtr(firstAddr, false); + + if (hasSecondAddr) + retVal += "\t" + EncodeDataPtr(secondAddr, false); + + if (addrs.length() > 0) + { + retVal += "\n:addrs\t" + addrs; + if (continuationData.length() > 0) + retVal += "\n:continuation\t" + continuationData; + } + } + } + else if (debugVis->mCollectionType == DebugVisualizerEntry::CollectionType_Dictionary) + { + BfTypedValue sizeValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mSize, dbgVisWildcardCaptures), &formatInfo); + BfTypedValue entriesPtrValue = EvaluateInContext(typedValue, debugVisualizers->DoStringReplace(debugVis->mEntries, dbgVisWildcardCaptures), &formatInfo); + + if ((sizeValue) && (entriesPtrValue) && (sizeValue.mType->IsInteger()) && (ValueToInt(sizeValue) > 0)) + { + String continuationData; + + BfType* valueType = entriesPtrValue.mType; + + int getItemCount = (int)BF_MIN(ValueToInt(sizeValue), 2LL); + + BfType* useTypedValType = typedValue.mType; + + String addrs; //TODO: = GetDictionaryItems(debugVis, useTypedValue, 0, -1, getItemCount, &continuationData); + addr_ce firstAddr = 0; + if (addrs.length() > 0) + { + const char* addrsPtr = addrs.c_str(); + firstAddr = DecodeTargetDataPtr(addrsPtr); + } + + String evalStr = "((comptype(" + StrFormat("%d", valueType->mTypeId) + "))0x{1}), na"; + + evalStr += ", refid=\"" + referenceId + ".[]\""; + if (isReadOnly) + evalStr += ", ne"; + retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)ValueToInt(sizeValue), 10000) + + "\t[{0}]\t" + evalStr + "\t" + EncodeDataPtr(firstAddr, false); + + if (addrs.length() > 0) + { + retVal += "\n:addrs\t" + addrs; + if (continuationData.length() > 0) + retVal += "\n:continuation\t" + continuationData; + } + } + } + + if (formatInfo.mExpandItemDepth == 0) + { + retVal += "\n[Raw View]\tthis,this=" + ptrUseDataStr + ", nv"; + } +} + +String CeDebugger::Evaluate(const StringImpl& expr, int callStackIdx, int cursorPos, int language, DwEvalExpressionFlags expressionFlags) +{ + CeFormatInfo formatInfo; + return Evaluate(expr, formatInfo, callStackIdx, cursorPos, language, expressionFlags); +} + +String CeDebugger::EvaluateContinue() +{ + return String(); +} + +void CeDebugger::EvaluateContinueKeep() +{ +} + +String CeDebugger::EvaluateToAddress(const StringImpl& expr, int callStackIdx, int cursorPos) +{ + return String(); +} + +String CeDebugger::EvaluateAtAddress(const StringImpl& expr, intptr atAddr, int cursorPos) +{ + return String(); +} + +String CeDebugger::GetAutoExpressions(int callStackIdx, uint64 memoryRangeStart, uint64 memoryRangeLen) +{ + return String(); +} + +String CeDebugger::GetAutoLocals(int callStackIdx, bool showRegs) +{ + String result; + + auto ceFrame = GetFrame(callStackIdx); + if (ceFrame != NULL) + { + if (ceFrame->mFunction->mDbgInfo != NULL) + { + for (auto& dbgVar : ceFrame->mFunction->mDbgInfo->mVariables) + { + result += dbgVar.mName; + result += "\n"; + } + } + } + + return result; +} + +String CeDebugger::CompactChildExpression(const StringImpl& expr, const StringImpl& parentExpr, int callStackIdx) +{ + return String(); +} + +String CeDebugger::GetProcessInfo() +{ + return String(); +} + +DebugVisualizerEntry* CeDebugger::FindVisualizerForType(BfType* dbgType, Array* wildcardCaptures) +{ + auto ceModule = mCeMachine->mCeModule; + + ceModule->PopulateType(dbgType); + auto entry = mDebugManager->mDebugVisualizers->FindEntryForType(ceModule->TypeToString(dbgType), DbgFlavor_Unknown, wildcardCaptures); + + if (entry == NULL) + { + auto typeInst = dbgType->ToTypeInstance(); + if ((typeInst != NULL) && (typeInst->mBaseType != NULL)) + entry = FindVisualizerForType(typeInst->mBaseType, wildcardCaptures); + } + + return entry; +} + +String CeDebugger::GetThreadInfo() +{ + return String(); +} + +void CeDebugger::SetActiveThread(int threadId) +{ +} + +int CeDebugger::GetActiveThread() +{ + return 0; +} + +void CeDebugger::FreezeThread(int threadId) +{ +} + +void CeDebugger::ThawThread(int threadId) +{ +} + +bool CeDebugger::IsActiveThreadWaiting() +{ + return false; +} + +void CeDebugger::ClearCallStack() +{ +} + +void CeDebugger::UpdateCallStack(bool slowEarlyOut) +{ +} + +int CeDebugger::GetCallStackCount() +{ + auto ceContext = mCeMachine->mCurContext; + if (ceContext == NULL) + return 0; + return ceContext->mCallStack.mSize; +} + +int CeDebugger::GetRequestedStackFrameIdx() +{ + return 0; +} + +int CeDebugger::GetBreakStackFrameIdx() +{ + return 0; +} + +bool CeDebugger::ReadMemory(intptr address, uint64 length, void* dest, bool local) +{ + auto ceContext = mCeMachine->mCurContext; + if (ceContext == NULL) + return false; + auto ptr = ceContext->GetMemoryPtr((addr_ce)address, (int32)length); + if (ptr == NULL) + return false; + memcpy(dest, ptr, length); + return true; +} + +bool CeDebugger::WriteMemory(intptr address, void* src, uint64 length) +{ + auto ceContext = mCeMachine->mCurContext; + if (ceContext == NULL) + return false; + auto ptr = ceContext->GetMemoryPtr((addr_ce)address, (int32)length); + if (ptr == NULL) + return false; + memcpy(ptr, src, length); + return true; +} + +DbgMemoryFlags CeDebugger::GetMemoryFlags(intptr address) +{ + return (DbgMemoryFlags)(DbgMemoryFlags_Read | DbgMemoryFlags_Write); +} + +void CeDebugger::UpdateRegisterUsage(int stackFrameIdx) +{ +} + +void CeDebugger::UpdateCallStackMethod(int stackFrameIdx) +{ +} + +void CeDebugger::GetCodeAddrInfo(intptr addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn) +{ +} + +void CeDebugger::GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx) +{ + *outThreadId = 0; + if (outStackIdx != NULL) + *outStackIdx = -1; + + auto ceContext = mCeMachine->mCurContext; + for (int i = 0; i < (int)ceContext->mCallStack.mSize; i++) + { + auto ceFrame = &ceContext->mCallStack[i]; + if ((addr_ce)addr > ceFrame->mFrameAddr) + { + if (outStackIdx != NULL) + *outStackIdx = (int)ceContext->mCallStack.mSize - i - 1; + } + } +} + +String CeDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* outFile, int32* outHotIdx, int32* outDefLineStart, int32* outDefLineEnd, int32* outLine, int32* outColumn, int32* outLanguage, int32* outStackSize, int8* outFlags) +{ + enum FrameFlags + { + FrameFlags_Optimized = 1, + FrameFlags_HasPendingDebugInfo = 2, + FrameFlags_CanGetOldSource = 4, + FrameFlags_WasHotReplaced = 8, + FrameFlags_HadError = 0x10 + }; + + auto ceContext = mCeMachine->mCurContext; + + *addr = 0; + *outFile = ""; + *outHotIdx = 0; + *outDefLineStart = -1; + *outDefLineEnd = -1; + *outLine = -1; + *outColumn = 0; + *outLanguage = DbgLanguage_Beef; + *outStackSize = 0; + *outFlags = 0; + + if (stackFrameIdx < ceContext->mCallStack.mSize) + { + int stackIdx = ceContext->mCallStack.mSize - stackFrameIdx - 1; + auto ceFrame = &ceContext->mCallStack[stackIdx]; + auto ceFunction = ceFrame->mFunction; + + if (ceFunction->mFailed) + *outFlags |= FrameFlags_HadError; + + int instIdx = (int)(ceFrame->mInstPtr - &ceFunction->mCode[0] - 2); + + BF_ASSERT(ceFunction->mId != -1); + *addr = ((intptr)ceFunction->mId << 32) | instIdx; + + CeEmitEntry* emitEntry = ceFunction->FindEmitEntry(instIdx); + + if (stackIdx > 0) + { + auto prevFrame = &ceContext->mCallStack[stackIdx - 1]; + *outStackSize = prevFrame->mStackAddr - ceFrame->mStackAddr; + } + else + { + *outStackSize = ceContext->mStackSize - ceFrame->mStackAddr; + } + + if (emitEntry != NULL) + { + if (emitEntry->mScope != -1) + *outFile = ceFunction->mDbgScopes[emitEntry->mScope].mFilePath; + *outLine = emitEntry->mLine; + *outColumn = emitEntry->mColumn; + } + + return ceContext->mCurModule->MethodToString(ceFrame->mFunction->mMethodInstance); + } + + return "?"; +} + +BfType* CeDebugger::FindType(const StringImpl& name) +{ + //TODO: + return NULL; +} + +String CeDebugger::Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) +{ + return String(); +} + +#define CE_GET(T) *((T*)(ptr += sizeof(T)) - 1) + +int CeDebugger::GetJmpState(int stackFrameIdx) +{ + if (stackFrameIdx != 0) + return -1; + + auto ceFrame = GetFrame(stackFrameIdx); + if (ceFrame == NULL) + return -1; + + int instIdx = ceFrame->GetInstIdx(); + + auto ptr = &ceFrame->mFunction->mCode[instIdx]; + auto op = CE_GET(CeOp); + switch (op) + { + case CeOp_Jmp: + return 1; + case CeOp_JmpIf: + case CeOp_JmpIfNot: + { + CE_GET(int32); + int frameOfs = CE_GET(int32); + bool willJump = *(bool*)(mCeMachine->mCurContext->mMemory.mVals + ceFrame->mFrameAddr + frameOfs); + if (op == CeOp_JmpIfNot) + willJump = !willJump; + return willJump ? 1 : 0; + } + } + + return -1; +} + +intptr CeDebugger::GetStackFrameCalleeAddr(int stackFrameIdx) +{ + return intptr(); +} + +String CeDebugger::GetStackMethodOwner(int stackFrameIdx, int& language) +{ + return String(); +} + +String CeDebugger::FindCodeAddresses(const StringImpl& fileName, int line, int column, bool allowAutoResolve) +{ + return String(); +} + +String CeDebugger::GetAddressSourceLocation(intptr address) +{ + return String(); +} + +String CeDebugger::GetAddressSymbolName(intptr address, bool demangle) +{ + return String(); +} + +String CeDebugger::DisassembleAtRaw(intptr address) +{ + return String(); +} + +String CeDebugger::DisassembleAt(intptr address) +{ + auto ceContext = mCeMachine->mCurContext; + + mCurDisasmFuncId = (int)(address >> 32); + UpdateBreakpointAddrs(); + + CeFunction* ceFunction = NULL; + if (!mCeMachine->mFunctionIdMap.TryGetValue(mCurDisasmFuncId, &ceFunction)) + return ""; + + CeDumpContext dumpCtx; + dumpCtx.mCeFunction = ceFunction; + dumpCtx.mStart = &ceFunction->mCode[0]; + dumpCtx.mPtr = dumpCtx.mStart; + dumpCtx.mEnd = dumpCtx.mPtr + ceFunction->mCode.mSize; + + uint8* start = dumpCtx.mStart; + + dumpCtx.mStr += StrFormat("T Frame Size: %d\n", ceFunction->mFrameSize); + dumpCtx.mStr += StrFormat("A %llX\n", (intptr)mCurDisasmFuncId << 32); + + int curEmitIdx = 0; + CeEmitEntry* prevEmitEntry = NULL; + CeEmitEntry* curEmitEntry = NULL; + + while (dumpCtx.mPtr < dumpCtx.mEnd) + { + int ofs = (int)(dumpCtx.mPtr - start); + + while ((curEmitIdx < ceFunction->mEmitTable.mSize - 1) && (ofs >= ceFunction->mEmitTable[curEmitIdx + 1].mCodePos)) + curEmitIdx++; + if (curEmitIdx < ceFunction->mEmitTable.mSize) + curEmitEntry = &ceFunction->mEmitTable[curEmitIdx]; + + if (prevEmitEntry != curEmitEntry) + { + if ((curEmitEntry != NULL) && (curEmitEntry->mLine != -1)) + { + if ((prevEmitEntry == NULL) || (curEmitEntry->mScope != prevEmitEntry->mScope)) + { + dumpCtx.mStr += StrFormat("S %s\n", ceFunction->mDbgScopes[curEmitEntry->mScope].mFilePath.c_str()); + } + + if ((prevEmitEntry != NULL) && (curEmitEntry->mScope == prevEmitEntry->mScope)) + { + dumpCtx.mStr += StrFormat("L %d %d\n", prevEmitEntry->mLine + 1, curEmitEntry->mLine - prevEmitEntry->mLine); + } + else + { + int startLine = BF_MAX(0, curEmitEntry->mLine - 5); + dumpCtx.mStr += StrFormat("L %d %d\n", startLine, curEmitEntry->mLine - startLine + 1); + } + + prevEmitEntry = curEmitEntry; + } + } + + dumpCtx.mStr += StrFormat("D %04X: ", ofs); + dumpCtx.Next(); + dumpCtx.mStr += "\n"; + + if (dumpCtx.mJmp != -1) + { + dumpCtx.mStr += StrFormat("J %X\n", dumpCtx.mJmp); + dumpCtx.mJmp = -1; + } + } + + return dumpCtx.mStr; +} + +String CeDebugger::FindLineCallAddresses(intptr address) +{ + return String(); +} + +String CeDebugger::GetCurrentException() +{ + return String(); +} + +String CeDebugger::GetModulesInfo() +{ + return String(); +} + +void CeDebugger::SetAliasPath(const StringImpl& origPath, const StringImpl& localPath) +{ +} + +void CeDebugger::CancelSymSrv() +{ +} + +bool CeDebugger::HasPendingDebugLoads() +{ + return false; +} + +int CeDebugger::LoadImageForModule(const StringImpl& moduleName, const StringImpl& debugFileName) +{ + return 0; +} + +int CeDebugger::LoadDebugInfoForModule(const StringImpl& moduleName) +{ + return 0; +} + +int CeDebugger::LoadDebugInfoForModule(const StringImpl& moduleName, const StringImpl& debugFileName) +{ + return 0; +} + +void CeDebugger::StopDebugging() +{ + mRunState = RunState_Terminating; + mCeMachine->mDebugEvent.Set(true); +} + +void CeDebugger::Terminate() +{ +} + +void CeDebugger::Detach() +{ + mRunState = RunState_Terminated; +} + +Profiler* CeDebugger::StartProfiling() +{ + return nullptr; +} + +Profiler* CeDebugger::PopProfiler() +{ + return nullptr; +} + +void CeDebugger::ReportMemory(MemReporter* memReporter) +{ +} + +bool CeDebugger::IsOnDemandDebugger() +{ + return true; +} diff --git a/IDEHelper/Compiler/CeDebugger.h b/IDEHelper/Compiler/CeDebugger.h new file mode 100644 index 00000000..d57caee6 --- /dev/null +++ b/IDEHelper/Compiler/CeDebugger.h @@ -0,0 +1,357 @@ +#pragma once + +#include "BfSystem.h" +#include "BfModule.h" +#include "BeefySysLib/util/Heap.h" +#include "BeefySysLib/util/AllocDebug.h" +#include "../Debugger.h" + +NS_BF_BEGIN + +class BfCompiler; +class CeFrame; +class CeExprEvaluator; +class CeContext; +class CeMachine; +class CeFunction; +class BfReducer; +class CeDebugger; +class DebugVisualizerEntry; + +class CeBreakpoint : public Breakpoint +{ +public: + uintptr mCurBindAddr; + bool mHasBound; + int mIdx; + +public: + CeBreakpoint() + { + mCurBindAddr = 1; + mHasBound = false; + mIdx = -1; + } + + virtual uintptr GetAddr() { return mCurBindAddr; } + virtual bool IsMemoryBreakpointBound() { return false; } +}; + +struct CeFormatInfo +{ + int mCallStackIdx; + bool mHidePointers; + bool mIgnoreDerivedClassInfo; + bool mNoVisualizers; + bool mNoMembers; + bool mRawString; + bool mNoEdit; + DbgTypeKindFlags mTypeKindFlags; + intptr mArrayLength; + intptr mOverrideCount; + intptr mMaxCount; + DwDisplayType mDisplayType; + int mTotalSummaryLength; + String mReferenceId; + String mSubjectExpr; + String mExpectedType; + String mNamespaceSearch; + int mExpandItemDepth; + BfTypedValue mExplicitThis; + + CeFormatInfo() + { + mCallStackIdx = -1; + mHidePointers = false; + mIgnoreDerivedClassInfo = false; + mRawString = false; + mNoVisualizers = false; + mNoMembers = false; + mNoEdit = false; + mTypeKindFlags = DbgTypeKindFlag_None; + mArrayLength = -1; + mOverrideCount = -1; + mMaxCount = -1; + mTotalSummaryLength = 0; + mDisplayType = DwDisplayType_NotSpecified; + mExpandItemDepth = 0; + } +}; + +class CeEvaluationContext +{ +public: + CeDebugger* mDebugger; + BfParser* mParser; + BfReducer* mReducer; + BfPassInstance* mPassInstance; + BfExprEvaluator* mExprEvaluator; + BfExpression* mExprNode; + BfTypedValue mResultOverride; + String mExprString; + + BfTypedValue mExplicitThis; + int mCallStackIdx; + +public: + CeEvaluationContext(CeDebugger* winDebugger, const StringImpl& expr, CeFormatInfo* formatInfo = NULL, BfTypedValue contextValue = BfTypedValue()); + void Init(CeDebugger* winDebugger, const StringImpl& expr, CeFormatInfo* formatInfo = NULL, BfTypedValue contextValue = BfTypedValue()); + bool HasExpression(); + ~CeEvaluationContext(); + BfTypedValue EvaluateInContext(BfTypedValue contextTypedValue); + String GetErrorStr(); + bool HadError(); +}; + +class CeDbgState +{ +public: + CeFrame* mActiveFrame; + CeContext* mCeContext; + BfTypedValue mExplicitThis; + DwEvalExpressionFlags mDbgExpressionFlags; + bool mHadSideEffects; + bool mBlockedSideEffects; + +public: + CeDbgState() + { + mActiveFrame = NULL; + mCeContext = NULL; + mDbgExpressionFlags = DwEvalExpressionFlag_None; + mHadSideEffects = false; + mBlockedSideEffects = false; + } +}; + +class CePendingExpr +{ +public: + int mThreadId; + BfParser* mParser; + BfType* mExplitType; + CeFormatInfo mFormatInfo; + DwEvalExpressionFlags mExpressionFlags; + int mCursorPos; + BfAstNode* mExprNode; + String mReferenceId; + int mCallStackIdx; + String mResult; + int mIdleTicks; + String mException; + + CePendingExpr(); + ~CePendingExpr(); +}; + +class CeFileInfo +{ +public: + Array mOrderedBreakpoints; +}; + +class CeDbgFieldEntry +{ +public: + BfType* mType; + int mDataOffset; + +public: + CeDbgFieldEntry() + { + mType = NULL; + mDataOffset = 0; + } +}; + +class CeDbgTypeInfo +{ +public: + struct ConstIntEntry + { + public: + int mFieldIdx; + int64 mVal; + }; + +public: + BfType* mType; + Array mFieldOffsets; + Array mConstIntEntries; +}; + +struct CeTypedValue +{ + addr_ce mAddr; + BfIRType mType; + + CeTypedValue() + { + mAddr = 0; + mType = BfIRType(); + } + + CeTypedValue(addr_ce addr, BfIRType type) + { + mAddr = addr; + mType = type; + } + + operator bool() const + { + return mType.mKind != BfIRTypeData::TypeKind_None; + } +}; + +class CeDebugger : public Debugger +{ +public: + BfCompiler* mCompiler; + CeMachine* mCeMachine; + DebugManager* mDebugManager; + CePendingExpr* mDebugPendingExpr; + CeDbgState* mCurDbgState; + Array mBreakpoints; + Dictionary mFileInfo; + Dictionary mDbgTypeInfoMap; + + CeEvaluationContext* mCurEvaluationContext; + CeBreakpoint* mActiveBreakpoint; + int mBreakpointVersion; + bool mBreakpointCacheDirty; + bool mBreakpointFramesDirty; + int mCurDisasmFuncId; + +public: + bool SetupStep(int frameIdx = 0); + CeFrame* GetFrame(int callStackIdx); + String EvaluateContinue(CePendingExpr* pendingExpr, BfPassInstance& bfPassInstance); + String Evaluate(const StringImpl& expr, CeFormatInfo formatInfo, int callStackIdx, int cursorPos, int language, DwEvalExpressionFlags expressionFlags); + DwDisplayInfo* GetDisplayInfo(const StringImpl& referenceId); + String GetMemberList(BfType* type, addr_ce addr, addr_ce addrInst, bool isStatic); + DebugVisualizerEntry* FindVisualizerForType(BfType* dbgType, Array* wildcardCaptures); + bool ParseFormatInfo(const StringImpl& formatInfoStr, CeFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExprString, String* errorString, BfTypedValue contextTypedValue = BfTypedValue()); + String MaybeQuoteFormatInfoParam(const StringImpl& str); + BfTypedValue EvaluateInContext(const BfTypedValue& contextTypedValue, const StringImpl& subExpr, CeFormatInfo* formatInfo = NULL, String* outReferenceId = NULL, String* outErrors = NULL); + void DbgVisFailed(DebugVisualizerEntry* debugVis, const StringImpl& evalString, const StringImpl& errors); + String GetArrayItems(DebugVisualizerEntry* debugVis, BfType* valueType, BfTypedValue& curNode, int& count, String* outContinuationData); + String GetLinkedListItems(DebugVisualizerEntry* debugVis, addr_ce endNodePtr, BfType* valueType, BfTypedValue& curNode, int& count, String* outContinuationData); + String GetDictionaryItems(DebugVisualizerEntry* debugVis, BfTypedValue dictValue, int bucketIdx, int nodeIdx, int& count, String* outContinuationData); + String GetTreeItems(DebugVisualizerEntry* debugVis, Array& parentList, BfType*& valueType, BfTypedValue& curNode, int count, String* outContinuationData); + bool EvalCondition(DebugVisualizerEntry* debugVis, BfTypedValue typedVal, CeFormatInfo& formatInfo, const StringImpl& condition, const Array& dbgVisWildcardCaptures, String& errorStr); + CeTypedValue GetAddr(BfConstant* constant); + CeTypedValue GetAddr(const BfTypedValue typeVal); + String ReadString(BfTypeCode charType, intptr addr, intptr maxLength, CeFormatInfo& formatInfo); + void ProcessEvalString(BfTypedValue useTypedValue, String& evalStr, String& displayString, CeFormatInfo& formatInfo, DebugVisualizerEntry* debugVis, bool limitLength); + String TypedValueToString(const BfTypedValue& typedValue, const StringImpl& expr, CeFormatInfo& formatFlags, bool fullPrecision = false); + void HandleCustomExpandedItems(String& retVal, DebugVisualizerEntry* debugVis, BfTypedValue typedValue, addr_ce addr, addr_ce addrInst, Array& dbgVisWildcardCaptures, CeFormatInfo& formatInfo); + void ClearBreakpointCache(); + void UpdateBreakpointCache(); + void UpdateBreakpointFrames(); + void UpdateBreakpointAddrs(); + void UpdateBreakpoints(CeFunction* ceFunction); + void Continue(); + CeDbgTypeInfo* GetDbgTypeInfo(int typeId); + CeDbgTypeInfo* GetDbgTypeInfo(BfIRType irType); + int64 ValueToInt(const BfTypedValue& typedVal); + BfType* FindType(const StringImpl& name); + +public: + CeDebugger(DebugManager* debugManager, BfCompiler* bfCompiler); + ~CeDebugger(); + + virtual void OutputMessage(const StringImpl& msg) override; + virtual void OutputRawMessage(const StringImpl& msg) override; + virtual int GetAddrSize() override; + virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override; + virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array& envBlock, bool hotSwapEnabled) override; + virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override; + virtual void Run() override; + virtual void HotLoad(const Array& objectFiles, int hotIdx) override; + virtual void InitiateHotResolve(DbgHotResolveFlags flags) override; + virtual intptr GetDbgAllocHeapSize() override; + virtual String GetDbgAllocInfo() override; + virtual void Update() override; + virtual void ContinueDebugEvent() override; + virtual void ForegroundTarget() override; + virtual Breakpoint* CreateBreakpoint(const StringImpl& fileName, int lineNum, int wantColumn, int instrOffset) override; + virtual Breakpoint* CreateMemoryBreakpoint(intptr addr, int byteCount) override; + virtual Breakpoint* CreateSymbolBreakpoint(const StringImpl& symbolName) override; + virtual Breakpoint* CreateAddressBreakpoint(intptr address) override; + virtual uintptr GetBreakpointAddr(Breakpoint* breakpoint) override; + virtual void CheckBreakpoint(Breakpoint* breakpoint) override; + virtual void HotBindBreakpoint(Breakpoint* wdBreakpoint, int lineNum, int hotIdx) override; + virtual void DeleteBreakpoint(Breakpoint* wdBreakpoint) override; + virtual void DetachBreakpoint(Breakpoint* wdBreakpoint) override; + virtual void MoveBreakpoint(Breakpoint* wdBreakpoint, int lineNum, int wantColumn, bool rebindNow) override; + virtual void MoveMemoryBreakpoint(Breakpoint* wdBreakpoint, intptr addr, int byteCount) override; + virtual void DisableBreakpoint(Breakpoint* wdBreakpoint) override; + virtual void SetBreakpointCondition(Breakpoint* wdBreakpoint, const StringImpl& condition) override; + virtual void SetBreakpointLogging(Breakpoint* wdBreakpoint, const StringImpl& logging, bool breakAfterLogging) override; + virtual Breakpoint* FindBreakpointAt(intptr address) override; + virtual Breakpoint* GetActiveBreakpoint() override; + virtual void BreakAll() override; + virtual bool TryRunContinue() override; + virtual void StepInto(bool inAssembly) override; + virtual void StepIntoSpecific(intptr addr) override; + virtual void StepOver(bool inAssembly) override; + virtual void StepOut(bool inAssembly) override; + virtual void SetNextStatement(bool inAssembly, const StringImpl& fileName, int64 lineNumOrAsmAddr, int wantColumn) override; + //virtual DbgTypedValue GetRegister(const StringImpl& regName, CPURegisters* registers, Array* regForms = NULL) override; + virtual String Evaluate(const StringImpl& expr, int callStackIdx, int cursorPos, int language, DwEvalExpressionFlags expressionFlags) override; + virtual String EvaluateContinue() override; + virtual void EvaluateContinueKeep() override; + virtual String EvaluateToAddress(const StringImpl& expr, int callStackIdx, int cursorPos) override; + virtual String EvaluateAtAddress(const StringImpl& expr, intptr atAddr, int cursorPos) override; + virtual String GetCollectionContinuation(const StringImpl& continuationData, int callStackIdx, int count) override; + virtual String GetAutoExpressions(int callStackIdx, uint64 memoryRangeStart, uint64 memoryRangeLen) override; + virtual String GetAutoLocals(int callStackIdx, bool showRegs) override; + virtual String CompactChildExpression(const StringImpl& expr, const StringImpl& parentExpr, int callStackIdx) override; + virtual String GetProcessInfo() override; + virtual String GetThreadInfo() override; + virtual void SetActiveThread(int threadId) override; + virtual int GetActiveThread() override; + virtual void FreezeThread(int threadId) override; + virtual void ThawThread(int threadId) override; + virtual bool IsActiveThreadWaiting() override; + virtual void ClearCallStack() override; + virtual void UpdateCallStack(bool slowEarlyOut = true) override; + virtual int GetCallStackCount() override; + virtual int GetRequestedStackFrameIdx() override; + virtual int GetBreakStackFrameIdx() override; + virtual bool ReadMemory(intptr address, uint64 length, void* dest, bool local = false) override; + virtual bool WriteMemory(intptr address, void* src, uint64 length) override; + virtual DbgMemoryFlags GetMemoryFlags(intptr address) override; + virtual void UpdateRegisterUsage(int stackFrameIdx) override; + virtual void UpdateCallStackMethod(int stackFrameIdx) override; + virtual void GetCodeAddrInfo(intptr addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn) override; + virtual void GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx) override; + virtual String GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* outFile, int32* outHotIdx, int32* outDefLineStart, int32* outDefLineEnd, int32* outLine, int32* outColumn, int32* outLanguage, int32* outStackSize, int8* outFlags) override; + virtual String Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) override; + virtual int GetJmpState(int stackFrameIdx) override; + virtual intptr GetStackFrameCalleeAddr(int stackFrameIdx) override; + virtual String GetStackMethodOwner(int stackFrameIdx, int& language) override; + virtual String FindCodeAddresses(const StringImpl& fileName, int line, int column, bool allowAutoResolve) override; + virtual String GetAddressSourceLocation(intptr address) override; + virtual String GetAddressSymbolName(intptr address, bool demangle) override; + virtual String DisassembleAtRaw(intptr address) override; + virtual String DisassembleAt(intptr address) override; + virtual String FindLineCallAddresses(intptr address) override; + virtual String GetCurrentException() override; + virtual String GetModulesInfo() override; + virtual void SetAliasPath(const StringImpl& origPath, const StringImpl& localPath) override; + virtual void CancelSymSrv() override; + virtual bool HasPendingDebugLoads() override; + virtual int LoadImageForModule(const StringImpl& moduleName, const StringImpl& debugFileName) override; + virtual int LoadDebugInfoForModule(const StringImpl& moduleName) override; + virtual int LoadDebugInfoForModule(const StringImpl& moduleName, const StringImpl& debugFileName) override; + virtual void StopDebugging() override; + virtual void Terminate() override; + virtual void Detach() override; + virtual Profiler* StartProfiling() override; + virtual Profiler* PopProfiler() override; // Profiler requested by target program + virtual void ReportMemory(MemReporter* memReporter) override; + virtual bool IsOnDemandDebugger() override; +}; + +NS_BF_END \ No newline at end of file diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 61af1a8b..a65f8787 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -1,4 +1,5 @@ #include "CeMachine.h" +#include "CeDebugger.h" #include "BfModule.h" #include "BfCompiler.h" #include "BfIRBuilder.h" @@ -8,6 +9,7 @@ #include "BfResolvePass.h" #include "../Backend/BeIRCodeGen.h" #include "BeefySysLib/platform/PlatformHelper.h" +#include "../DebugManager.h" extern "C" { @@ -35,70 +37,71 @@ struct CeOpInfo }; #define CEOPINFO_SIZED_1(OPNAME, OPINFOA) \ - {OPNAME "_8", OPINFOA}, \ - {OPNAME "_16", OPINFOA}, \ - {OPNAME "_32", OPINFOA}, \ - {OPNAME "_64", OPINFOA}, \ + {OPNAME "_8", OPINFOA##8}, \ + {OPNAME "_16", OPINFOA##16}, \ + {OPNAME "_32", OPINFOA##32}, \ + {OPNAME "_64", OPINFOA##64}, \ {OPNAME "_X", OPINFOA, CEOI_None, CEOI_None, CEOI_None, CeOpInfoFlag_SizeX} #define CEOPINFO_SIZED_2(OPNAME, OPINFOA, OPINFOB) \ - {OPNAME "_8", OPINFOA, OPINFOB}, \ - {OPNAME "_16", OPINFOA, OPINFOB}, \ - {OPNAME "_32", OPINFOA, OPINFOB}, \ - {OPNAME "_64", OPINFOA, OPINFOB}, \ + {OPNAME "_8", OPINFOA##8, OPINFOB##8}, \ + {OPNAME "_16", OPINFOA##16, OPINFOB##16}, \ + {OPNAME "_32", OPINFOA##32, OPINFOB##32}, \ + {OPNAME "_64", OPINFOA##64, OPINFOB##64}, \ {OPNAME "_X", OPINFOA, OPINFOB, CEOI_None, CEOI_None, CeOpInfoFlag_SizeX} #define CEOPINFO_SIZED_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_8", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_16", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_64", OPINFOA, OPINFOB, OPINFOC}, \ + {OPNAME "_8", OPINFOA##8, OPINFOB##8, OPINFOC##8}, \ + {OPNAME "_16", OPINFOA##16, OPINFOB##16, OPINFOC##16}, \ + {OPNAME "_32", OPINFOA##32, OPINFOB##32, OPINFOC##32}, \ + {OPNAME "_64", OPINFOA##64, OPINFOB##64, OPINFOC##64}, \ {OPNAME "_X", OPINFOA, OPINFOB, OPINFOC, CEOI_None, CeOpInfoFlag_SizeX} #define CEOPINFO_SIZED_NUMERIC_2(OPNAME, OPINFOA, OPINFOB) \ - {OPNAME "_I8", OPINFOA, OPINFOB}, \ - {OPNAME "_I16", OPINFOA, OPINFOB}, \ - {OPNAME "_I32", OPINFOA, OPINFOB}, \ - {OPNAME "_I64", OPINFOA, OPINFOB} + {OPNAME "_I8", OPINFOA##8, OPINFOB##8}, \ + {OPNAME "_I16", OPINFOA##16, OPINFOB##16}, \ + {OPNAME "_I32", OPINFOA##32, OPINFOB##32}, \ + {OPNAME "_I64", OPINFOA##64, OPINFOB##64} #define CEOPINFO_SIZED_NUMERIC_PLUSF_2(OPNAME, OPINFOA, OPINFOB) \ - {OPNAME "_I8", OPINFOA, OPINFOB}, \ - {OPNAME "_I16", OPINFOA, OPINFOB}, \ - {OPNAME "_I32", OPINFOA, OPINFOB}, \ - {OPNAME "_I64", OPINFOA, OPINFOB}, \ - {OPNAME "_F32", OPINFOA, OPINFOB}, \ - {OPNAME "_F64", OPINFOA, OPINFOB} + {OPNAME "_I8", OPINFOA##8, OPINFOB##8}, \ + {OPNAME "_I16", OPINFOA##16, OPINFOB##16}, \ + {OPNAME "_I32", OPINFOA##32, OPINFOB##32}, \ + {OPNAME "_I64", OPINFOA##64, OPINFOB##64}, \ + {OPNAME "_F32", OPINFOA##F32, OPINFOB##F64}, \ + {OPNAME "_F64", OPINFOA##F64, OPINFOB##F64} #define CEOPINFO_SIZED_NUMERIC_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_I8", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I16", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I64", OPINFOA, OPINFOB, OPINFOC} + {OPNAME "_I8", OPINFOA##8, OPINFOB##8, OPINFOC##8}, \ + {OPNAME "_I16", OPINFOA##16, OPINFOB##16, OPINFOC##16}, \ + {OPNAME "_I32", OPINFOA##32, OPINFOB##32, OPINFOC##32}, \ + {OPNAME "_I64", OPINFOA##64, OPINFOB##64, OPINFOC##64} #define CEOPINFO_SIZED_UNUMERIC_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_U8", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_U16", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_U32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_U64", OPINFOA, OPINFOB, OPINFOC} + {OPNAME "_U8", OPINFOA##8, OPINFOB##8, OPINFOC##8}, \ + {OPNAME "_U16", OPINFOA##16, OPINFOB##16, OPINFOC##16}, \ + {OPNAME "_U32", OPINFOA##32, OPINFOB##32, OPINFOC##32}, \ + {OPNAME "_U64", OPINFOA##64, OPINFOB##64, OPINFOC##64} #define CEOPINFO_SIZED_NUMERIC_PLUSF_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_I8", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I16", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_I64", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_F32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_F64", OPINFOA, OPINFOB, OPINFOC} + {OPNAME "_I8", OPINFOA##8, OPINFOB##8, OPINFOC##8}, \ + {OPNAME "_I16", OPINFOA##16, OPINFOB##16, OPINFOC##16}, \ + {OPNAME "_I32", OPINFOA##32, OPINFOB##32, OPINFOC##32}, \ + {OPNAME "_I64", OPINFOA##64, OPINFOB##64, OPINFOC##64}, \ + {OPNAME "_F32", OPINFOA##F32, OPINFOB##F32, OPINFOC##F32}, \ + {OPNAME "_F64", OPINFOA##F64, OPINFOB##F64, OPINFOC##F64} #define CEOPINFO_SIZED_FLOAT_2(OPNAME, OPINFOA, OPINFOB) \ - {OPNAME "_F32", OPINFOA, OPINFOB}, \ - {OPNAME "_F64", OPINFOA, OPINFOB} + {OPNAME "_F32", OPINFOA##F32, OPINFOB##F32}, \ + {OPNAME "_F64", OPINFOA##F64, OPINFOB##F64} #define CEOPINFO_SIZED_FLOAT_3(OPNAME, OPINFOA, OPINFOB, OPINFOC) \ - {OPNAME "_F32", OPINFOA, OPINFOB, OPINFOC}, \ - {OPNAME "_F64", OPINFOA, OPINFOB, OPINFOC} + {OPNAME "_F32", OPINFOA##F32, OPINFOB##F32, OPINFOC##F32}, \ + {OPNAME "_F64", OPINFOA##F64, OPINFOB##F64, OPINFOC##F64} static CeOpInfo gOpInfo[] = { {"InvalidOp"}, + {"DbgBreak"}, {"Ret"}, {"SetRet", CEOI_None, CEOI_IMM32}, {"Jmp", CEOI_None, CEOI_JMPREL}, - {"JmpIf", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, - {"JmpIfNot", CEOI_None, CEOI_JMPREL, CEOI_FrameRef}, + {"JmpIf", CEOI_None, CEOI_JMPREL, CEOI_FrameRef8}, + {"JmpIfNot", CEOI_None, CEOI_JMPREL, CEOI_FrameRef8}, {"Error", CEOI_None, CEOI_IMM32}, {"DynamicCastCheck", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM32}, {"GetReflectType", CEOI_FrameRef, CEOI_IMM32}, @@ -116,10 +119,10 @@ static CeOpInfo gOpInfo[] = {"ConstDataRef", CEOI_FrameRef, CEOI_IMM32}, {"Zero", CEOI_None, CEOI_FrameRef, CEOI_IMM32}, - {"Const_8", CEOI_FrameRef, CEOI_IMM8}, - {"Const_16", CEOI_FrameRef, CEOI_IMM16}, - {"Const_32", CEOI_FrameRef, CEOI_IMM32}, - {"Const_64", CEOI_FrameRef, CEOI_IMM64}, + {"Const_8", CEOI_FrameRef8, CEOI_IMM8}, + {"Const_16", CEOI_FrameRef16, CEOI_IMM16}, + {"Const_32", CEOI_FrameRef32, CEOI_IMM32}, + {"Const_64", CEOI_FrameRef64, CEOI_IMM64}, {"Const_X", CEOI_FrameRef, CEOI_IMM_VAR}, CEOPINFO_SIZED_2("Load", CEOI_FrameRef, CEOI_FrameRef), @@ -140,52 +143,52 @@ static CeOpInfo gOpInfo[] = {"GetMethod_IFace", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM32, CEOI_IMM32}, {"Call", CEOI_None, CEOI_FrameRef}, - {"CeOp_Conv_I8_I16", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I8_I32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I8_I64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I8_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I8_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I16_I32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I16_I64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I16_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I16_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I32_I64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I32_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I32_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I64_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_I64_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U8_U16", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U8_U32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U8_U64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U8_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U8_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U16_U32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U16_U64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U16_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U16_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U32_U64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U32_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U32_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U64_F32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_U64_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F32_I8", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F32_I16", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F32_I32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F32_I64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F32_F64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F64_I8", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F64_I16", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F64_I32", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F64_I64", CEOI_FrameRef, CEOI_FrameRef}, - {"CeOp_Conv_F64_F32", CEOI_FrameRef, CEOI_FrameRef}, + {"CeOp_Conv_I8_I16", CEOI_FrameRef16, CEOI_FrameRef8}, + {"CeOp_Conv_I8_I32", CEOI_FrameRef32, CEOI_FrameRef8}, + {"CeOp_Conv_I8_I64", CEOI_FrameRef64, CEOI_FrameRef8}, + {"CeOp_Conv_I8_F32", CEOI_FrameRefF32, CEOI_FrameRef8}, + {"CeOp_Conv_I8_F64", CEOI_FrameRefF64, CEOI_FrameRef8}, + {"CeOp_Conv_I16_I32", CEOI_FrameRef32, CEOI_FrameRef16}, + {"CeOp_Conv_I16_I64", CEOI_FrameRef64, CEOI_FrameRef16}, + {"CeOp_Conv_I16_F32", CEOI_FrameRefF32, CEOI_FrameRef16}, + {"CeOp_Conv_I16_F64", CEOI_FrameRefF64, CEOI_FrameRef16}, + {"CeOp_Conv_I32_I64", CEOI_FrameRef64, CEOI_FrameRef32}, + {"CeOp_Conv_I32_F32", CEOI_FrameRefF32, CEOI_FrameRef32}, + {"CeOp_Conv_I32_F64", CEOI_FrameRefF64, CEOI_FrameRef32}, + {"CeOp_Conv_I64_F32", CEOI_FrameRefF32, CEOI_FrameRef64}, + {"CeOp_Conv_I64_F64", CEOI_FrameRefF64, CEOI_FrameRef64}, + {"CeOp_Conv_U8_U16", CEOI_FrameRef16, CEOI_FrameRef8}, + {"CeOp_Conv_U8_U32", CEOI_FrameRef32, CEOI_FrameRef8}, + {"CeOp_Conv_U8_U64", CEOI_FrameRef64, CEOI_FrameRef8}, + {"CeOp_Conv_U8_F32", CEOI_FrameRefF32, CEOI_FrameRef8}, + {"CeOp_Conv_U8_F64", CEOI_FrameRefF64, CEOI_FrameRef8}, + {"CeOp_Conv_U16_U32", CEOI_FrameRef32, CEOI_FrameRef16}, + {"CeOp_Conv_U16_U64", CEOI_FrameRef64, CEOI_FrameRef16}, + {"CeOp_Conv_U16_F32", CEOI_FrameRefF32, CEOI_FrameRef16}, + {"CeOp_Conv_U16_F64", CEOI_FrameRefF64, CEOI_FrameRef16}, + {"CeOp_Conv_U32_U64", CEOI_FrameRef64, CEOI_FrameRef32}, + {"CeOp_Conv_U32_F32", CEOI_FrameRefF32, CEOI_FrameRef32}, + {"CeOp_Conv_U32_F64", CEOI_FrameRefF64, CEOI_FrameRef32}, + {"CeOp_Conv_U64_F32", CEOI_FrameRefF32, CEOI_FrameRef64}, + {"CeOp_Conv_U64_F64", CEOI_FrameRefF64, CEOI_FrameRef64}, + {"CeOp_Conv_F32_I8", CEOI_FrameRef8, CEOI_FrameRefF32}, + {"CeOp_Conv_F32_I16", CEOI_FrameRef16, CEOI_FrameRefF32}, + {"CeOp_Conv_F32_I32", CEOI_FrameRef32, CEOI_FrameRefF32}, + {"CeOp_Conv_F32_I64", CEOI_FrameRef64, CEOI_FrameRefF32}, + {"CeOp_Conv_F32_F64", CEOI_FrameRefF32, CEOI_FrameRefF32}, + {"CeOp_Conv_F64_I8", CEOI_FrameRef8, CEOI_FrameRefF64}, + {"CeOp_Conv_F64_I16", CEOI_FrameRef16, CEOI_FrameRefF64}, + {"CeOp_Conv_F64_I32", CEOI_FrameRef32, CEOI_FrameRefF64}, + {"CeOp_Conv_F64_I64", CEOI_FrameRef64, CEOI_FrameRefF64}, + {"CeOp_Conv_F64_F32", CEOI_FrameRefF32, CEOI_FrameRefF64}, CEOPINFO_SIZED_NUMERIC_PLUSF_2("Abs", CEOI_FrameRef, CEOI_FrameRef), - {"AddConst_I8", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM8}, - {"AddConst_I16", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM16}, - {"AddConst_I32", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM32}, - {"AddConst_I64", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMM64}, - {"AddConst_F32", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMMF32}, - {"AddConst_F64", CEOI_FrameRef, CEOI_FrameRef, CEOI_IMMF64}, + {"AddConst_I8", CEOI_FrameRef8, CEOI_FrameRef8, CEOI_IMM8}, + {"AddConst_I16", CEOI_FrameRef16, CEOI_FrameRef16, CEOI_IMM16}, + {"AddConst_I32", CEOI_FrameRef32, CEOI_FrameRef32, CEOI_IMM32}, + {"AddConst_I64", CEOI_FrameRef64, CEOI_FrameRef64, CEOI_IMM64}, + {"AddConst_F32", CEOI_FrameRefF32, CEOI_FrameRefF32, CEOI_IMMF32}, + {"AddConst_F64", CEOI_FrameRefF64, CEOI_FrameRefF64, CEOI_IMMF64}, CEOPINFO_SIZED_NUMERIC_PLUSF_3("Add", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("Sub", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_3("Mul", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), @@ -230,7 +233,7 @@ static CeOpInfo gOpInfo[] = CEOPINFO_SIZED_NUMERIC_PLUSF_3("Cmp_SGE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_3("Cmp_UGE", CEOI_FrameRef, CEOI_FrameRef, CEOI_FrameRef), CEOPINFO_SIZED_NUMERIC_PLUSF_2("Neg", CEOI_FrameRef, CEOI_FrameRef), - {"Not_I1", CEOI_FrameRef, CEOI_FrameRef}, + {"Not_I1", CEOI_FrameRef8, CEOI_FrameRef8}, CEOPINFO_SIZED_NUMERIC_2("Not", CEOI_FrameRef, CEOI_FrameRef), }; @@ -328,6 +331,7 @@ CeFunction::~CeFunction() for (auto innerFunc : mInnerFunctions) delete innerFunc; delete mCeInnerFunctionInfo; + delete mDbgInfo; BfLogSys(mCeMachine->mCompiler->mSystem, "CeFunction::~CeFunction %p\n", this); } @@ -347,6 +351,46 @@ void CeFunction::Print() OutputDebugStrF("Code for %s:\n%s\n", methodName.c_str(), dumpCtx.mStr.c_str()); } +void CeFunction::UnbindBreakpoints() +{ + for (auto kv : mBreakpoints) + mCode[kv.mKey] = kv.mValue.mPrevOpCode; + mBreakpoints.Clear(); +} + +CeEmitEntry* CeFunction::FindEmitEntry(int instIdx, int* entryIdx) +{ + int i = 0; + CeEmitEntry* emitEntry = NULL; + + if (!mCode.IsEmpty()) + { + int lo = 0; + int hi = mEmitTable.size() - 1; + while (lo <= hi) + { + i = (lo + hi) / 2; + emitEntry = &mEmitTable.mVals[i]; + //int c = midVal <=> value; + if (emitEntry->mCodePos == instIdx) break; + if (emitEntry->mCodePos < instIdx) + lo = i + 1; + else + hi = i - 1; + } + if ((emitEntry != NULL) && (emitEntry->mCodePos > instIdx) && (i > 0)) + { + emitEntry = &mEmitTable.mVals[i - 1]; + if (entryIdx != NULL) + *entryIdx = i - 1; + } + else if (entryIdx != NULL) + *entryIdx = i; + } + + return emitEntry; +} + ////////////////////////////////////////////////////////////////////////// CeFunctionInfo::~CeFunctionInfo() @@ -363,13 +407,52 @@ void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind) switch (operandInfoKind) { case CEOI_FrameRef: + case CEOI_FrameRef8: + case CEOI_FrameRef16: + case CEOI_FrameRef32: + case CEOI_FrameRef64: + case CEOI_FrameRefF32: + case CEOI_FrameRefF64: { int32 addr = CE_GET(int32); + + if (mCeFunction->mDbgInfo != NULL) + { + CeDbgVariable* dbgVar = NULL; + if (mVarMap.TryGetValue(addr, &dbgVar)) + { + mStr += dbgVar->mName; + mStr += "@"; + } + } + + switch (operandInfoKind) + { + case CEOI_FrameRef8: + mStr += "int8"; + break; + case CEOI_FrameRef16: + mStr += "int16"; + break; + case CEOI_FrameRef32: + mStr += "int32"; + break; + case CEOI_FrameRef64: + mStr += "int64"; + break; + case CEOI_FrameRefF32: + mStr += "float"; + break; + case CEOI_FrameRefF64: + mStr += "double"; + break; + } + char str[64]; if (addr >= 0) - sprintf(str, "FR+0x%X", addr); + sprintf(str, "[FR+0x%X]", addr); else - sprintf(str, "FR-0x%X", -addr); + sprintf(str, "[FR-0x%X]", -addr); mStr += str; } break; @@ -427,11 +510,100 @@ void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind) char str[64]; sprintf(str, "JMP:%04X", (int32)(val + (mPtr - mStart))); mStr += str; + + mJmp = (int32)(val + (mPtr - mStart)); } break; } } +void CeDumpContext::Next() +{ + CeOp op = CE_GET(CeOp); + + if (op == CeOp_DbgBreak) + { + int instIdx = mPtr - mCeFunction->mCode.mVals - 2; + CeBreakpointBind* breakpointEntry = NULL; + if (mCeFunction->mBreakpoints.TryGetValue(instIdx, &breakpointEntry)) + { + op = breakpointEntry->mPrevOpCode; + } + } + + CeOpInfo& opInfo = gOpInfo[op]; + + auto argPtr = mPtr; + + if (mCeFunction->mDbgInfo != NULL) + { + for (auto& dbgVar : mCeFunction->mDbgInfo->mVariables) + { + mVarMap[dbgVar.mValue.mFrameOfs] = &dbgVar; + } + } + + int32 sizeX = -1; + if ((opInfo.mFlags & CeOpInfoFlag_SizeX) != 0) + { + sizeX = CE_GET(int); + } + + if (opInfo.mResultKind != CEOI_None) + { + DumpOperandInfo(opInfo.mResultKind); + mStr += " = "; + } + + mStr += opInfo.mName; + + if (sizeX != -1) + { + mStr += StrFormat(":%d", sizeX); + } + + if (opInfo.mOperandA != CEOI_None) + { + mStr += " "; + DumpOperandInfo(opInfo.mOperandA); + } + + if (opInfo.mOperandB != CEOI_None) + { + mStr += ", "; + DumpOperandInfo(opInfo.mOperandB); + } + + if (opInfo.mOperandC != CEOI_None) + { + mStr += ", "; + DumpOperandInfo(opInfo.mOperandC); + } + + auto endPtr = mPtr; + + if (op == CeOp_GetMethod) + { + mPtr = argPtr; + CE_GET(int32); + int methodIdx = CE_GET(int32); + auto& callEntry = mCeFunction->mCallTable[methodIdx]; + auto methodInstance = callEntry.mFunctionInfo->mMethodInstance; + auto ceModule = mCeFunction->mCeMachine->mCeModule; + if (!callEntry.mFunctionInfo->mMethodRef.IsNull()) + { + auto methodRef = callEntry.mFunctionInfo->mMethodRef; + auto methodDef = methodRef.mTypeInstance->mTypeDef->mMethods[methodRef.mMethodNum]; + methodInstance = ceModule->GetMethodInstance(methodRef.mTypeInstance, methodDef, + methodRef.mMethodGenericArguments).mMethodInstance; + } + if (methodInstance != NULL) + mStr += StrFormat(" ; %s", ceModule->MethodToString(methodInstance).c_str()); + + mPtr = endPtr; + } +} + void CeDumpContext::Dump() { if (!mCeFunction->mGenError.IsEmpty()) @@ -451,52 +623,12 @@ void CeDumpContext::Dump() if (curEmitIdx < mCeFunction->mEmitTable.mSize) curEmitEntry = &mCeFunction->mEmitTable[curEmitIdx]; - CeOp op = CE_GET(CeOp); - - CeOpInfo& opInfo = gOpInfo[op]; - mStr += StrFormat("%04X: ", ofs); + Next(); - int32 sizeX = -1; - if ((opInfo.mFlags & CeOpInfoFlag_SizeX) != 0) - { - sizeX = CE_GET(int); - } - - if (opInfo.mResultKind != CEOI_None) - { - DumpOperandInfo(opInfo.mResultKind); - mStr += " = "; - } - - mStr += opInfo.mName; - - if (sizeX != -1) - { - mStr += StrFormat(":%d", sizeX); - } - - if (opInfo.mOperandA != CEOI_None) - { - mStr += " "; - DumpOperandInfo(opInfo.mOperandA); - } - - if (opInfo.mOperandB != CEOI_None) - { - mStr += ", "; - DumpOperandInfo(opInfo.mOperandB); - } - - if (opInfo.mOperandC != CEOI_None) - { - mStr += ", "; - DumpOperandInfo(opInfo.mOperandC); - } - - if ((curEmitEntry != NULL) && (curEmitEntry->mFile != -1)) + if ((curEmitEntry != NULL) && (curEmitEntry->mScope != -1)) { - mStr += StrFormat(" @%d[%s:%d]", curEmitIdx, GetFileName(mCeFunction->mFiles[curEmitEntry->mFile]).c_str(), + mStr += StrFormat(" @%d[%s:%d]", curEmitIdx, GetFileName(mCeFunction->mDbgScopes[curEmitEntry->mScope].mFilePath).c_str(), curEmitEntry->mLine + 1, curEmitEntry->mColumn + 1); } @@ -1066,9 +1198,34 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme } } break; - case BeGEPConstant::TypeId: + case BeGEP1Constant::TypeId: { - auto gepConstant = (BeGEPConstant*)value; + auto gepConstant = (BeGEP1Constant*)value; + + auto mcVal = GetOperand(gepConstant->mTarget); + + BePointerType* ptrType = (BePointerType*)mcVal.mType; + BF_ASSERT(ptrType->mTypeCode == BeTypeCode_Pointer); + + auto result = mcVal; + + // We assume we never do both an idx0 and idx1 at once. Fix if we change that. + int64 byteOffset = 0; + BeType* elementType = NULL; + byteOffset += gepConstant->mIdx0 * ptrType->mElementType->mSize; + + result = FrameAlloc(ptrType); + EmitSizedOp(CeOp_AddConst_I8, mPtrSize); + EmitFrameOffset(result); + EmitFrameOffset(mcVal); + Emit(&byteOffset, mPtrSize); + + return result; + } + break; + case BeGEP2Constant::TypeId: + { + auto gepConstant = (BeGEP2Constant*)value; auto mcVal = GetOperand(gepConstant->mTarget); @@ -1293,7 +1450,8 @@ void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance auto irCodeGen = mCeMachine->mCeModule->mBfIRBuilder->mBeIRCodeGen; auto irBuilder = mCeMachine->mCeModule->mBfIRBuilder; auto beModule = irCodeGen->mBeModule; - + beModule->mCeMachine = mCeMachine; + dupMethodInstance->mIsReified = true; dupMethodInstance->mInCEMachine = false; // Only have the original one @@ -1383,6 +1541,8 @@ void CeBuilder::Build() innerFunction->mCeInnerFunctionInfo->mName = beFunction->mName; innerFunction->mCeInnerFunctionInfo->mBeFunction = beFunction; innerFunction->mCeInnerFunctionInfo->mOwner = mCeFunction; + if (mCeMachine->mDebugger != NULL) + innerFunction->mDbgInfo = new CeDbgFunctionInfo(); mInnerFunctionMap[beFunction] = (int)mCeFunction->mInnerFunctions.size(); mCeFunction->mInnerFunctions.Add(innerFunction); mCeMachine->MapFunctionId(innerFunction); @@ -1518,8 +1678,7 @@ void CeBuilder::Build() switch (instType) { case BeEnsureInstructionAtInst::TypeId: - case BeNopInst::TypeId: - case BeDbgDeclareInst::TypeId: + case BeNopInst::TypeId: case BeLifetimeStartInst::TypeId: case BeLifetimeEndInst::TypeId: case BeLifetimeExtendInst::TypeId: @@ -2547,7 +2706,9 @@ void CeBuilder::Build() case BfIRIntrinsic_AtomicXor: EmitBinaryOp(CeOp_Xor_I8, CeOp_InvalidOp, GetOperand(castedInst->mArgs[0].mValue), GetOperand(castedInst->mArgs[1].mValue), result); break; - + case BfIRIntrinsic_DebugTrap: + Emit(CeOp_DbgBreak); + break; default: Emit(CeOp_Error); Emit((int32)CeErrorKind_Intrinsic); @@ -2842,6 +3003,24 @@ void CeBuilder::Build() EmitFrameOffset(mcValue); Emit((int32)castedInst->mTypeId); } + break; + case BeDbgDeclareInst::TypeId: + { + auto castedInst = (BeDbgDeclareInst*)inst; + auto mcValue = GetOperand(castedInst->mValue, true); + + if (mCeFunction->mDbgInfo != NULL) + { + if (auto dbgTypeId = BeValueDynCast(castedInst->mDbgVar->mType)) + { + CeDbgVariable dbgVariable; + dbgVariable.mName = castedInst->mDbgVar->mName; + dbgVariable.mValue = mcValue; + dbgVariable.mType = mCeMachine->mCeModule->mContext->mTypes[dbgTypeId->mTypeId]; + mCeFunction->mDbgInfo->mVariables.Add(dbgVariable); + } + } + } break; default: Fail("Unhandled instruction"); @@ -2852,10 +3031,8 @@ void CeBuilder::Build() mValueToOperand[inst] = result; if ((startCodePos != GetCodePos()) && (prevEmitDbgPos != mCurDbgLoc)) - { - prevEmitDbgPos = mCurDbgLoc; - - int fileIdx = -1; + { + int scopeIdx = -1; BeDbgFile* dbgFile = NULL; if (mCurDbgLoc != NULL) { @@ -2863,31 +3040,42 @@ void CeBuilder::Build() int* valuePtr = NULL; if (mDbgFileMap.TryAdd(dbgFile, NULL, &valuePtr)) { - fileIdx = (int)mCeFunction->mFiles.size(); + scopeIdx = (int)mCeFunction->mDbgScopes.size(); String filePath = dbgFile->mDirectory; filePath.Append(DIR_SEP_CHAR); filePath += dbgFile->mFileName; - mCeFunction->mFiles.Add(filePath); - *valuePtr = fileIdx; + CeDbgScope dbgScope; + dbgScope.mFilePath = filePath; + mCeFunction->mDbgScopes.Add(dbgScope); + *valuePtr = scopeIdx; } else - fileIdx = *valuePtr; + scopeIdx = *valuePtr; } CeEmitEntry emitEntry; emitEntry.mCodePos = startCodePos; - emitEntry.mFile = fileIdx; + emitEntry.mScope = scopeIdx; if (mCurDbgLoc != NULL) { emitEntry.mLine = mCurDbgLoc->mLine; emitEntry.mColumn = mCurDbgLoc->mColumn; } + else if (!mCeFunction->mEmitTable.IsEmpty()) + { + auto& prevEmitEntry = mCeFunction->mEmitTable.back(); + emitEntry.mScope = prevEmitEntry.mScope; + emitEntry.mLine = prevEmitEntry.mLine; + emitEntry.mColumn = -1; + } else { emitEntry.mLine = -1; emitEntry.mColumn = -1; } mCeFunction->mEmitTable.Add(emitEntry); + + prevEmitDbgPos = mCurDbgLoc; } } } @@ -2969,30 +3157,8 @@ BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) auto* ceFrame = (isHeadEntry) ? &curFrame : &mCallStack[stackIdx]; auto ceFunction = ceFrame->mFunction; - - int i = 0; - CeEmitEntry* emitEntry = NULL; - - if (!ceFunction->mCode.IsEmpty()) - { - int lo = 0; - int hi = ceFunction->mEmitTable.size() - 1; - int instIdx = ceFrame->mInstPtr - &ceFunction->mCode[0] - 1; - while (lo <= hi) - { - i = (lo + hi) / 2; - emitEntry = &ceFunction->mEmitTable.mVals[i]; - //int c = midVal <=> value; - if (emitEntry->mCodePos == instIdx) break; - if (emitEntry->mCodePos < instIdx) - lo = i + 1; - else - hi = i - 1; - } - if ((emitEntry != NULL) && (emitEntry->mCodePos > instIdx) && (i > 0)) - emitEntry = &ceFunction->mEmitTable.mVals[i - 1]; - } - + + CeEmitEntry* emitEntry = ceFunction->FindEmitEntry(ceFrame->mInstPtr - &ceFunction->mCode[0] - 1); StringT<256> err; if (isHeadEntry) { @@ -3024,15 +3190,15 @@ BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) } } - if ((emitEntry != NULL) && (emitEntry->mFile != -1)) + if ((emitEntry != NULL) && (emitEntry->mScope != -1)) { - err += StrFormat(" at line% d:%d in %s", emitEntry->mLine + 1, emitEntry->mColumn + 1, ceFunction->mFiles[emitEntry->mFile].c_str()); + err += StrFormat(" at line% d:%d in %s", emitEntry->mLine + 1, emitEntry->mColumn + 1, ceFunction->mDbgScopes[emitEntry->mScope].mFilePath.c_str()); auto moreInfo = passInstance->MoreInfo(err, mCeMachine->mCeModule->mCompiler->GetAutoComplete() != NULL); if ((moreInfo != NULL)) { BfErrorLocation* location = new BfErrorLocation(); - location->mFile = ceFunction->mFiles[emitEntry->mFile]; + location->mFile = ceFunction->mDbgScopes[emitEntry->mScope].mFilePath; location->mLine = emitEntry->mLine; location->mColumn = emitEntry->mColumn; moreInfo->mLocation = location; @@ -3402,6 +3568,13 @@ bool CeContext::CheckMemory(addr_ce addr, int32 size) return true; } +uint8* CeContext::GetMemoryPtr(addr_ce addr, int32 size) +{ + if (CheckMemory(addr, size)) + return mMemory.mVals + addr; + return NULL; +} + bool CeContext::GetStringFromAddr(addr_ce strInstAddr, StringImpl& str) { if (!CheckMemory(strInstAddr, 0)) @@ -4420,8 +4593,6 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } } - BF_ASSERT(mCallStack.IsEmpty()); - auto methodDef = methodInstance->mMethodDef; if (mCeMachine->mCeModule == NULL) @@ -4451,9 +4622,19 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns if (ceFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(ceFunction, NULL); + Array prevCallStack; + auto stackPtr = &mMemory[0] + mStackSize; auto* memStart = &mMemory[0]; + if (!mCallStack.IsEmpty()) + { + BF_ASSERT((flags & CeEvalFlags_DbgCall) != 0); + prevCallStack = mCallStack; + stackPtr = &mMemory[0] + mCallStack.back().mStackAddr; + mCallStack.Clear(); + } + BfTypeInstance* thisType = methodInstance->GetOwner(); addr_ce allocThisInstAddr = 0; addr_ce allocThisAddr = 0; @@ -4709,6 +4890,12 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns moduleCurTypeInstance.Restore(); module->AddDependency(methodInstance->GetOwner(), module->mCurTypeInstance, BfDependencyMap::DependencyFlag_ConstEval); + if (!prevCallStack.IsEmpty()) + { + BF_ASSERT((flags& CeEvalFlags_DbgCall) != 0); + mCallStack = prevCallStack; + } + return returnValue; } @@ -4978,6 +5165,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* bool needsFunctionIds = ceModule->mSystem->mPtrSize != 8; int32 ptrSize = ceModule->mSystem->mPtrSize; + volatile bool* specialCheckPtr = &mCeMachine->mSpecialCheck; volatile bool* fastFinishPtr = &mCeMachine->mCompiler->mFastFinish; volatile bool* cancelingPtr = &mCeMachine->mCompiler->mCanceling; @@ -5002,10 +5190,48 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* stackPtr += memOffset; framePtr += memOffset; }; + + auto _DbgPause = [&]() + { + if (mCeMachine->mDebugger != NULL) + { + mCeMachine->mCritSect.Lock(); + mCallStack.Add(_GetCurFrame()); + mCeMachine->mDbgPaused = true; + mCeMachine->mCritSect.Unlock(); + + mCeMachine->mDebugEvent.WaitFor(); + + mCeMachine->mCritSect.Lock(); + mCeMachine->mDbgPaused = false; + mCallStack.pop_back(); + mCeMachine->mCritSect.Unlock(); + + _FixVariables(); + } + }; auto _Fail = [&](const StringImpl& error) { Fail(_GetCurFrame(), error); + + if (mCeMachine->mDebugger != NULL) + { + mCeMachine->mDebugger->OutputRawMessage(StrFormat("error %s", error.c_str())); + _DbgPause(); + } + }; + + auto _CheckFastFinish = [&]() + { + if (*fastFinishPtr) + return true; + if (mCeMachine->mDbgWantBreak) + { + mCeMachine->mDbgWantBreak = false; + _DbgPause(); + } + return false; }; auto _CheckFunction = [&](CeFunction* checkFunction, bool& handled) @@ -5016,6 +5242,17 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* return false; } + if (mCeMachine->mDebugger != NULL) + { + if (checkFunction->mBreakpointVersion != mCeMachine->mDebugger->mBreakpointVersion) + mCeMachine->mDebugger->UpdateBreakpoints(checkFunction); + } + else if (checkFunction->mBreakpointVersion != 0) + { + checkFunction->UnbindBreakpoints(); + checkFunction->mBreakpointVersion = 0; + } + if (checkFunction->mFunctionKind != CeFunctionKind_Normal) { if (checkFunction->mFunctionKind == CeFunctionKind_OOB) @@ -5064,7 +5301,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* char* strPtr = (char*)(ptrVal + memStart); String str; str.Insert(0, strPtr, size); - OutputDebugStr(str); + + if (mCeMachine->mDebugger != NULL) + mCeMachine->mDebugger->OutputMessage(str); + else + OutputDebugStr(str); } else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) { @@ -5468,7 +5709,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* int32 sleepMS = *(int32*)((uint8*)stackPtr); while (sleepMS > 0) { - if (*fastFinishPtr) + if (_CheckFastFinish()) break; if (sleepMS > 20) @@ -6206,7 +6447,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* int timeLeft = waitMS; do { - if (*fastFinishPtr) + if (_CheckFastFinish()) { result = false; break; @@ -6346,9 +6587,12 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* return true; } - - if (!checkFunction->mFailed) + if (!checkFunction->mFailed) return true; + + if (mCeMachine->mDebugger != NULL) + _Fail(StrFormat("Attempting to call failed method '%s'", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); + auto error = Fail(_GetCurFrame(), StrFormat("Method call preparation '%s' failed", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); if ((error != NULL) && (!checkFunction->mGenError.IsEmpty())) mCeMachine->mCompiler->mPassInstance->MoreInfo("Comptime method generation error: " + checkFunction->mGenError); @@ -6365,31 +6609,134 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } int callCount = 0; - int instIdx = 0; + int instCount = 0; CE_CHECKSTACK(); while (true) { - if (*fastFinishPtr) - { - if ((mCurModule != NULL) && (mCurModule->mCurTypeInstance != NULL)) - { - mCurModule->mCurTypeInstance->mRebuildFlags = (BfTypeRebuildFlags)(mCurModule->mCurTypeInstance->mRebuildFlags | BfTypeRebuildFlag_ConstEvalCancelled); - mCurModule->DeferRebuildType(mCurModule->mCurTypeInstance); - } - if (*cancelingPtr) - { - if ((mCurModule == NULL) || (mCurModule->mCurTypeInstance == NULL)) - _Fail("Comptime evaluation canceled"); - } - return false; - } - - ++instIdx; + ++instCount; CeOp op = CE_GETINST(CeOp); + + if (*specialCheckPtr) + { + SpecialCheck: + if (*fastFinishPtr) + { + if ((mCurModule != NULL) && (mCurModule->mCurTypeInstance != NULL)) + { + mCurModule->mCurTypeInstance->mRebuildFlags = (BfTypeRebuildFlags)(mCurModule->mCurTypeInstance->mRebuildFlags | BfTypeRebuildFlag_ConstEvalCancelled); + mCurModule->DeferRebuildType(mCurModule->mCurTypeInstance); + } + if (*cancelingPtr) + { + if ((mCurModule == NULL) || (mCurModule->mCurTypeInstance == NULL)) + _Fail("Comptime evaluation canceled"); + } + return false; + } + + bool wantsStop = false; + + if (mCeMachine->mStepState.mKind != CeStepState::Kind_None) + { + int curDepth = mCallStack.mSize + 1; + + int instIdx = instPtr - ceFunction->mCode.mVals - 1; + + switch (mCeMachine->mStepState.mKind) + { + case CeStepState::Kind_StepInfo: + if (curDepth != mCeMachine->mStepState.mStartDepth) + wantsStop = true; + else if (instIdx >= mCeMachine->mStepState.mNextInstIdx) + wantsStop = true; + break; + case CeStepState::Kind_StepInfo_Asm: + wantsStop = true; + break; + case CeStepState::Kind_StepOver: + if (curDepth < mCeMachine->mStepState.mStartDepth) + wantsStop = true; + else if ((mCeMachine->mStepState.mStartDepth == curDepth) && (instIdx >= mCeMachine->mStepState.mNextInstIdx)) + wantsStop = true; + break; + case CeStepState::Kind_StepOver_Asm: + if (curDepth < mCeMachine->mStepState.mStartDepth) + wantsStop = true; + else if (curDepth == mCeMachine->mStepState.mStartDepth) + wantsStop = true; + break; + case CeStepState::Kind_StepOut: + if (curDepth < mCeMachine->mStepState.mStartDepth) + wantsStop = true; + else if ((curDepth == mCeMachine->mStepState.mStartDepth) && (instIdx >= mCeMachine->mStepState.mNextInstIdx)) + wantsStop = true; + break; + case CeStepState::Kind_StepOut_Asm: + if (curDepth <= mCeMachine->mStepState.mStartDepth) + wantsStop = true; + break; + case CeStepState::Kind_Jmp: + instPtr = &ceFunction->mCode[mCeMachine->mStepState.mNextInstIdx]; + op = CE_GETINST(CeOp); + wantsStop = true; + break; + } + } + else if (mCeMachine->mDbgWantBreak) + { + wantsStop = true; + } + else if ((mCeMachine->mDebugger != NULL) && (mCeMachine->mDebugger->mBreakpointFramesDirty)) + { + AutoCrit autoCrit(mCeMachine->mCritSect); + mCallStack.Add(_GetCurFrame()); + mCeMachine->mDebugger->UpdateBreakpointFrames(); + mCallStack.pop_back(); + } + else + *specialCheckPtr = false; + + if (wantsStop) + { + mCeMachine->mDbgWantBreak = false; + mCeMachine->mStepState.mKind = CeStepState::Kind_None; + _DbgPause(); + if (mCeMachine->mStepState.mKind == CeStepState::Kind_Jmp) + goto SpecialCheck; + // We may have changed breakpoints so we need to re-read + instPtr -= sizeof(CeOp); + op = CE_GETINST(CeOp); + } + } + + OpSwitch: switch (op) { + case CeOp_DbgBreak: + { + bool foundBreakpoint = false; + + if (mCeMachine->mDebugger != NULL) + { + AutoCrit autoCrit(mCeMachine->mCritSect); + int instIdx = instPtr - ceFunction->mCode.mVals - 2; + CeBreakpointBind* breakpointEntry = NULL; + if (ceFunction->mBreakpoints.TryGetValue(instIdx, &breakpointEntry)) + { + op = breakpointEntry->mPrevOpCode; + foundBreakpoint = true; + } + } + + _DbgPause(); + if (mCeMachine->mStepState.mKind == CeStepState::Kind_Jmp) + goto SpecialCheck; + if (foundBreakpoint) + goto OpSwitch; + } + break; case CeOp_Ret: { if (mCallStack.mSize == 0) @@ -7770,6 +8117,11 @@ CeMachine::CeMachine(BfCompiler* compiler) mTempReducer = NULL; mTempPassInstance = NULL; + mDebugger = NULL; + mDbgPaused = false; + mDbgWantBreak = false; + mSpecialCheck = false; + BfLogSys(mCompiler->mSystem, "CeMachine::CeMachine %p\n", this); } @@ -7830,7 +8182,7 @@ void CeMachine::Init() mCeModule->mBfIRBuilder = new BfIRBuilder(mCeModule); mCeModule->mBfIRBuilder->mDbgVerifyCodeGen = true; mCeModule->FinishInit(); - mCeModule->mBfIRBuilder->mHasDebugInfo = false; // Only line info + mCeModule->mBfIRBuilder->mHasDebugInfo = mDebugger != NULL; // We will still have line info even if this is false mCeModule->mBfIRBuilder->mIgnoreWrites = false; mCeModule->mWantsIRIgnoreWrites = false; } @@ -7852,8 +8204,10 @@ BeModule* CeMachine::GetBeModule() void CeMachine::CompileStarted() { mRevisionExecuteTime = 0; + mSpecialCheck = false; mRevision++; - mMethodBindRevision++; + mMethodBindRevision++; + mDbgWantBreak = false; if (mCeModule != NULL) { delete mCeModule; @@ -7870,6 +8224,73 @@ void CeMachine::CompileDone() mMethodInstanceSet.Clear(); } +#define CE_SIZE_GET(T) *((T*)(ptr += sizeof(T)) - 1) + +int CeMachine::GetInstSize(CeFunction* ceFunction, int instIdx) +{ + auto ptr = &ceFunction->mCode[instIdx]; + auto startPtr = ptr; + + auto _HandleOperand = [&](CeOperandInfoKind kind) + { + switch (kind) + { + case CEOI_FrameRef: + case CEOI_FrameRef8: + case CEOI_FrameRef16: + case CEOI_FrameRef32: + case CEOI_FrameRef64: + case CEOI_FrameRefF32: + case CEOI_FrameRefF64: + ptr += 4; + break; + case CEOI_IMM8: + ptr += 1; + break; + case CEOI_IMM16: + ptr += 2; + break; + case CEOI_IMM32: + ptr += 4; + break; + case CEOI_IMM64: + ptr += 8; + break; + case CEOI_IMM_VAR: + { + int32 size = CE_SIZE_GET(int32); + ptr += size; + } + break; + case CEOI_JMPREL: + ptr += 4; + break; + default: + BF_ASSERT("Unhandled"); + } + }; + + auto op = CE_SIZE_GET(CeOp); + + if (op == CeOp_DbgBreak) + { + CeBreakpointBind* breakpointEntry = NULL; + if (ceFunction->mBreakpoints.TryGetValue(instIdx, &breakpointEntry)) + op = breakpointEntry->mPrevOpCode; + } + + CeOpInfo& opInfo = gOpInfo[op]; + + _HandleOperand(opInfo.mResultKind); + if ((opInfo.mFlags & CeOpInfoFlag_SizeX) != 0) + ptr += 4; + _HandleOperand(opInfo.mOperandA); + _HandleOperand(opInfo.mOperandB); + _HandleOperand(opInfo.mOperandC); + + return (int)(ptr - startPtr); +} + void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo) { ceFunctionInfo->mRefCount--; @@ -8070,7 +8491,7 @@ CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constV if (result != CeErrorKind_None) return result; } - else if (auto constGep = BeValueDynCast(constVal)) + else if (auto constGep = BeValueDynCast(constVal)) { if (auto globalVar = BeValueDynCast(constGep->mTarget)) { @@ -8547,7 +8968,7 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder void CeMachine::MapFunctionId(CeFunction* ceFunction) { - if (mCeModule->mSystem->mPtrSize == 8) + if ((mCeModule->mSystem->mPtrSize == 8) && (mDebugger == NULL)) return; ceFunction->mId = ++mCurFunctionId; mFunctionIdMap[ceFunction->mId] = ceFunction; @@ -8619,6 +9040,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f ceFunction->mIsVarReturn = methodInstance->mReturnType->IsVar(); ceFunction->mCeFunctionInfo = ceFunctionInfo; ceFunction->mMethodInstance = methodInstance; + if (mDebugger != NULL) + ceFunction->mDbgInfo = new CeDbgFunctionInfo(); ceFunctionInfo->mMethodInstance = methodInstance; ceFunctionInfo->mCeFunction = ceFunction; MapFunctionId(ceFunction); diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index dd324811..f39a2e82 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -24,6 +24,8 @@ class BeSwitchInst; class BeGlobalVariable; class CeMachine; class CeFunction; +class CeDebugger; +class CeBreakpoint; #define CEOP_SIZED(OPNAME) \ CeOp_##OPNAME##_8, \ @@ -69,6 +71,7 @@ enum CeErrorKind enum CeOp : int16 { CeOp_InvalidOp, + CeOp_DbgBreak, CeOp_Ret, CeOp_SetRetType, CeOp_Jmp, @@ -204,10 +207,55 @@ enum CeOp : int16 CeOp_COUNT }; +enum CeOperandKind +{ + CeOperandKind_None, + CeOperandKind_FrameOfs, + CeOperandKind_AllocaAddr, + CeOperandKind_Block, + CeOperandKind_Immediate, + CeOperandKind_ConstStructTableIdx, + CeOperandKind_CallTableIdx +}; + +class CeOperand +{ +public: + CeOperandKind mKind; + union + { + int mFrameOfs; + int mBlockIdx; + int mImmediate; + int mCallTableIdx; + int mStructTableIdx; + BeConstant* mConstant; + }; + BeType* mType; + +public: + CeOperand() + { + mKind = CeOperandKind_None; + mFrameOfs = 0; + mType = NULL; + } + + operator bool() const + { + return mKind != CeOperandKind_None; + } + + bool IsImmediate() + { + return mKind == CeOperandKind_Immediate; + } +}; + struct CeEmitEntry { int mCodePos; - int mFile; + int mScope; int mLine; int mColumn; }; @@ -490,6 +538,40 @@ public: } }; +class CeDbgVariable +{ +public: + String mName; + CeOperand mValue; + BfType* mType; +}; + +class CeDbgFunctionInfo +{ +public: + Array mVariables; +}; + +class CeBreakpointBind +{ +public: + CeOp mPrevOpCode; + CeBreakpoint* mBreakpoint; +}; + +struct CeDbgScope +{ +public: + String mFilePath; + int mInlinedAt; + +public: + CeDbgScope() + { + mInlinedAt = -1; + } +}; + class CeFunction { public: @@ -511,7 +593,7 @@ public: bool mFailed; bool mIsVarReturn; Array mCode; - Array mFiles; + Array mDbgScopes; Array mEmitTable; Array mCallTable; Array mStringTable; @@ -519,10 +601,13 @@ public: Array mStaticFieldTable; Array mTypeTable; Array mInnerFunctions; + Dictionary mBreakpoints; String mGenError; int mFrameSize; int mMaxReturnSize; - int mId; + int mId; + int mBreakpointVersion; + CeDbgFunctionInfo* mDbgInfo; public: CeFunction() @@ -537,11 +622,15 @@ public: mIsVarReturn = false; mFrameSize = 0; mMaxReturnSize = 0; + mBreakpointVersion = 0; mId = -1; + mDbgInfo = NULL; } ~CeFunction(); void Print(); + void UnbindBreakpoints(); + CeEmitEntry* FindEmitEntry(int loc, int* entryIdx = NULL); }; enum CeEvalFlags @@ -551,52 +640,8 @@ enum CeEvalFlags CeEvalFlags_PersistantError = 2, CeEvalFlags_DeferIfNotOnlyError = 4, CeEvalFlags_NoRebuild = 8, - CeEvalFlags_ForceReturnThis = 0x10 -}; - -enum CeOperandKind -{ - CeOperandKind_None, - CeOperandKind_FrameOfs, - CeOperandKind_AllocaAddr, - CeOperandKind_Block, - CeOperandKind_Immediate, - CeOperandKind_ConstStructTableIdx, - CeOperandKind_CallTableIdx -}; - -class CeOperand -{ -public: - CeOperandKind mKind; - union - { - int mFrameOfs; - int mBlockIdx; - int mImmediate; - int mCallTableIdx; - int mStructTableIdx; - BeConstant* mConstant; - }; - BeType* mType; - -public: - CeOperand() - { - mKind = CeOperandKind_None; - mFrameOfs = 0; - mType = NULL; - } - - operator bool() const - { - return mKind != CeOperandKind_None; - } - - bool IsImmediate() - { - return mKind == CeOperandKind_Immediate; - } + CeEvalFlags_ForceReturnThis = 0x10, + CeEvalFlags_DbgCall = 0x20 }; #define BF_CE_DEFAULT_STACK_SIZE 4*1024*1024 @@ -609,7 +654,21 @@ public: enum CeOperandInfoKind { CEOI_None, + CEOI_None8 = CEOI_None, + CEOI_None16 = CEOI_None, + CEOI_None32 = CEOI_None, + CEOI_None64 = CEOI_None, + CEOI_NoneF32 = CEOI_None, + CEOI_NoneF64 = CEOI_None, + CEOI_FrameRef, + CEOI_FrameRef8, + CEOI_FrameRef16, + CEOI_FrameRef32, + CEOI_FrameRef64, + CEOI_FrameRefF32, + CEOI_FrameRefF64, + CEOI_IMM8, CEOI_IMM16, CEOI_IMM32, @@ -631,18 +690,24 @@ enum CeSizeClass class CeDumpContext { - - public: + Dictionary mVarMap; CeFunction* mCeFunction; String mStr; uint8* mStart; uint8* mPtr; uint8* mEnd; + int mJmp; public: + CeDumpContext() + { + mJmp = -1; + } + void DumpOperandInfo(CeOperandInfoKind operandInfoKind); + void Next(); void Dump(); }; @@ -760,6 +825,11 @@ public: mInstPtr = NULL; mReturnType = NULL; } + + int GetInstIdx() + { + return (int)(mInstPtr - &mFunction->mCode[0] - 2); + } }; class CeStaticFieldInfo @@ -909,6 +979,7 @@ public: BfType* GetBfType(BfIRType irType); void PrepareConstStructEntry(CeConstStructData& constStructData); bool CheckMemory(addr_ce addr, int32 size); + uint8* GetMemoryPtr(addr_ce addr, int32 size); bool GetStringFromAddr(addr_ce strInstAddr, StringImpl& str); bool GetStringFromStringView(addr_ce addr, StringImpl& str); bool GetCustomAttribute(BfModule* module, BfIRConstHolder* constHolder, BfCustomAttributes* customAttributes, int attributeIdx, addr_ce resultAddr); @@ -928,12 +999,40 @@ struct CeTypeInfo int mRevision; }; +class CeStepState +{ +public: + enum Kind + { + Kind_None, + Kind_StepOver, + Kind_StepOver_Asm, + Kind_StepInfo, + Kind_StepInfo_Asm, + Kind_StepOut, + Kind_StepOut_Asm, + Kind_Jmp + }; + + Kind mKind; + int mNextInstIdx; + int mStartDepth; + +public: + CeStepState() + { + mKind = Kind_None; + mNextInstIdx = -1; + mStartDepth = 0; + } +}; + class CeMachine { public: Dictionary mFunctions; Dictionary mNamedFunctionMap; - Dictionary mFunctionIdMap; // Only used for 32-bit + Dictionary mFunctionIdMap; // Only used for 32-bit and debugging Dictionary mTypeInfoMap; HashSet mMethodInstanceSet; HashSet mFieldInstanceSet; @@ -959,6 +1058,14 @@ public: BfReducer* mTempReducer; BfPassInstance* mTempPassInstance; + CritSect mCritSect; + SyncEvent mDebugEvent; + CeStepState mStepState; + CeDebugger* mDebugger; + bool mDbgPaused; + bool mSpecialCheck; + bool mDbgWantBreak; + public: CeMachine(BfCompiler* compiler); ~CeMachine(); @@ -967,6 +1074,7 @@ public: BeContext* GetBeContext(); BeModule* GetBeModule(); + int GetInstSize(CeFunction* ceFunction, int instIdx); void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo); void RemoveFunc(CeFunction* ceFunction); void RemoveMethod(BfMethodInstance* methodInstance); diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 42f41dca..3e58fca9 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -7676,7 +7676,7 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue if (bitCount <= 0) return argValues[0]; - int64 andBits = (0x8000000000000000LL) >> ((argValues[0].mType->GetByteCount() - 8) * 8 + bitCount - 1); + int64 andBits = (0x8000000000000000LL) >> ((argValues[0].mType->GetByteCount() - 8) * 8 + bitCount - 1); DbgTypedValue result; result.mType = argValues[0].mType; result.mInt64 = val & ~andBits; diff --git a/IDEHelper/DbgExprEvaluator.h b/IDEHelper/DbgExprEvaluator.h index a8a85333..5bd19731 100644 --- a/IDEHelper/DbgExprEvaluator.h +++ b/IDEHelper/DbgExprEvaluator.h @@ -184,6 +184,49 @@ public: } }; +struct DwFormatInfo +{ + int mCallStackIdx; + bool mHidePointers; + bool mIgnoreDerivedClassInfo; + bool mNoVisualizers; + bool mNoMembers; + bool mRawString; + bool mNoEdit; + DbgTypeKindFlags mTypeKindFlags; + intptr mArrayLength; + intptr mOverrideCount; + intptr mMaxCount; + DwDisplayType mDisplayType; + DbgTypedValue mExplicitThis; + int mTotalSummaryLength; + String mReferenceId; + String mSubjectExpr; + String mExpectedType; + String mNamespaceSearch; + int mExpandItemDepth; + DbgLanguage mLanguage; + + DwFormatInfo() + { + mCallStackIdx = -1; + mHidePointers = false; + mIgnoreDerivedClassInfo = false; + mRawString = false; + mNoVisualizers = false; + mNoMembers = false; + mNoEdit = false; + mTypeKindFlags = DbgTypeKindFlag_None; + mArrayLength = -1; + mOverrideCount = -1; + mMaxCount = -1; + mTotalSummaryLength = 0; + mDisplayType = DwDisplayType_NotSpecified; + mExpandItemDepth = 0; + mLanguage = DbgLanguage_Unknown; + } +}; + struct DbgMethodArgument { DbgTypedValue mTypedValue; diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index 992363da..0ca03c8e 100644 --- a/IDEHelper/DebugManager.cpp +++ b/IDEHelper/DebugManager.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/ErrorHandling.h" #include "BeefySysLib/util/BeefPerf.h" #include "NetManager.h" +#include "Compiler/CeDebugger.h" #ifdef BF_PLATFORM_WINDOWS #include "DbgMiniDump.h" @@ -79,7 +80,7 @@ DebugManager::DebugManager() mStepOverExternalFiles = false; mDebugger32 = NULL; - mDebugger64 = NULL; + mDebugger64 = NULL; mNetManager = new NetManager(); mNetManager->mDebugManager = this; @@ -97,14 +98,20 @@ DebugManager::DebugManager() DebugManager::~DebugManager() { + if ((gDebugger != NULL) && (gDebugger->IsOnDemandDebugger())) + { + delete gDebugger; + gDebugger = NULL; + } + delete mNetManager; delete mDebugger64; - delete mDebugger32; + delete mDebugger32; /*for (auto stepFilter : mStepFilters) { }*/ - delete mDebugVisualizers; + delete mDebugVisualizers; } void DebugManager::OutputMessage(const StringImpl& msg) @@ -779,6 +786,12 @@ BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* return true; } +BF_EXPORT bool BF_CALLTYPE Debugger_ComptimeAttach(void* bfCompiler) +{ + gDebugger = new CeDebugger(gDebugManager, (BfCompiler*)bfCompiler); + return true; +} + BF_EXPORT void BF_CALLTYPE Debugger_SetSymSrvOptions(const char* symCacheDir, const char* symSrvStr, int flags) { Array symServers; @@ -1021,7 +1034,7 @@ BF_EXPORT uintptr BF_CALLTYPE Breakpoint_GetAddress(Breakpoint* wdBreakpoint, Br { if (outLinkedSibling != NULL) *outLinkedSibling = wdBreakpoint->mLinkedSibling; - return wdBreakpoint->GetAddr(); + return gDebugger->GetBreakpointAddr(wdBreakpoint); } BF_EXPORT bool BF_CALLTYPE Breakpoint_IsMemoryBreakpointBound(Breakpoint* wdBreakpoint) diff --git a/IDEHelper/DebugManager.h b/IDEHelper/DebugManager.h index 29017fbf..2f8658b9 100644 --- a/IDEHelper/DebugManager.h +++ b/IDEHelper/DebugManager.h @@ -65,7 +65,7 @@ class DebugManager { public: Debugger* mDebugger32; - Debugger* mDebugger64; + Debugger* mDebugger64; CritSect mCritSect; Dictionary mStepFilters; diff --git a/IDEHelper/Debugger.h b/IDEHelper/Debugger.h index 0f9495ee..4e716806 100644 --- a/IDEHelper/Debugger.h +++ b/IDEHelper/Debugger.h @@ -62,6 +62,13 @@ public: virtual bool IsMemoryBreakpointBound() = 0; }; + +enum DbgTypeKindFlags +{ + DbgTypeKindFlag_None = 0, + DbgTypeKindFlag_Int = 1 +}; + enum DwDisplayType : int8 { DwDisplayType_NotSpecified, @@ -282,6 +289,7 @@ public: virtual void SetBreakpointLogging(Breakpoint* wdBreakpoint, const StringImpl& logging, bool breakAfterLogging) = 0; virtual Breakpoint* FindBreakpointAt(intptr address) = 0; virtual Breakpoint* GetActiveBreakpoint() = 0; + virtual uintptr GetBreakpointAddr(Breakpoint* breakpoint) { return breakpoint->GetAddr(); } virtual void BreakAll() = 0; virtual bool TryRunContinue() = 0; virtual void StepInto(bool inAssembly) = 0; @@ -343,7 +351,7 @@ public: virtual Profiler* StartProfiling() = 0; virtual Profiler* PopProfiler() = 0; // Profiler requested by target program virtual void ReportMemory(MemReporter* memReporter) = 0; - virtual bool IsOnDemandDebugger() = 0; + virtual bool IsOnDemandDebugger() = 0; }; class Profiler diff --git a/IDEHelper/IDEHelper.vcxproj b/IDEHelper/IDEHelper.vcxproj index dca41ae5..48c8a48e 100644 --- a/IDEHelper/IDEHelper.vcxproj +++ b/IDEHelper/IDEHelper.vcxproj @@ -331,6 +331,7 @@ + @@ -399,6 +400,7 @@ + diff --git a/IDEHelper/IDEHelper.vcxproj.filters b/IDEHelper/IDEHelper.vcxproj.filters index 5f026346..5bba44be 100644 --- a/IDEHelper/IDEHelper.vcxproj.filters +++ b/IDEHelper/IDEHelper.vcxproj.filters @@ -214,6 +214,9 @@ Compiler + + Compiler + @@ -405,5 +408,8 @@ third_party + + Compiler + \ No newline at end of file diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index ee043644..679cf777 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -5825,7 +5825,7 @@ bool WinDebugger::EvalCondition(DebugVisualizerEntry* debugVis, DbgCompileUnit* return false; } - return evalResult.mBool; + return evalResult.mBool; } String WinDebugger::GetArrayItems(DbgCompileUnit* dbgCompileUnit, DebugVisualizerEntry* debugVis, DbgType* valueType, DbgTypedValue& curNode, int& count, String* outContinuationData) @@ -8156,7 +8156,7 @@ String WinDebugger::DbgTypedValueToString(const DbgTypedValue& origTypedValue, c displayString += "{ " + firstRet + " }"; else displayString += bigRet; - } + } DbgType* memberListType = actualType; bool memberListForceCast = false; @@ -8231,7 +8231,7 @@ String WinDebugger::DbgTypedValueToString(const DbgTypedValue& origTypedValue, c return ""; } - retVal += "\n" + displayType->ToString(DbgLanguage_Unknown, true); + retVal += "\n" + displayType->ToString(DbgLanguage_Unknown, true); memberListType = innerType; } @@ -11026,6 +11026,7 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o FrameFlags_HasPendingDebugInfo = 2, FrameFlags_CanGetOldSource = 4, FrameFlags_WasHotReplaced = 8, + FrameFlags_HadError = 0x10 }; AutoCrit autoCrit(mDebugManager->mCritSect); diff --git a/IDEHelper/WinDebugger.h b/IDEHelper/WinDebugger.h index 8cb9f511..29ef5767 100644 --- a/IDEHelper/WinDebugger.h +++ b/IDEHelper/WinDebugger.h @@ -272,55 +272,6 @@ public: } }; -enum DbgTypeKindFlags -{ - DbgTypeKindFlag_None = 0, - DbgTypeKindFlag_Int = 1 -}; - -struct DwFormatInfo -{ - int mCallStackIdx; - bool mHidePointers; - bool mIgnoreDerivedClassInfo; - bool mNoVisualizers; - bool mNoMembers; - bool mRawString; - bool mNoEdit; - DbgTypeKindFlags mTypeKindFlags; - intptr mArrayLength; - intptr mOverrideCount; - intptr mMaxCount; - DwDisplayType mDisplayType; - DbgTypedValue mExplicitThis; - int mTotalSummaryLength; - String mReferenceId; - String mSubjectExpr; - String mExpectedType; - String mNamespaceSearch; - int mExpandItemDepth; - DbgLanguage mLanguage; - - DwFormatInfo() - { - mCallStackIdx = -1; - mHidePointers = false; - mIgnoreDerivedClassInfo = false; - mRawString = false; - mNoVisualizers = false; - mNoMembers = false; - mNoEdit = false; - mTypeKindFlags = DbgTypeKindFlag_None; - mArrayLength = -1; - mOverrideCount = -1; - mMaxCount = -1; - mTotalSummaryLength = 0; - mDisplayType = DwDisplayType_NotSpecified; - mExpandItemDepth = 0; - mLanguage = DbgLanguage_Unknown; - } -}; - class DbgPendingExpr { public: @@ -411,6 +362,8 @@ public: } }; +struct DwFormatInfo; + class WinDebugger : public Debugger { public: @@ -542,7 +495,7 @@ public: bool SetHotJump(DbgSubprogram* oldSubprogram, addr_target newTarget, int newTargetSize); DbgSubprogram* TryFollowHotJump(DbgSubprogram* subprogram, addr_target addr); - bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue()); + bool ParseFormatInfo(DbgModule* dbgModule, const StringImpl& formatInfoStr, DwFormatInfo* formatInfo, BfPassInstance* bfPassInstance, int* assignExprOffset, String* assignExpr = NULL, String* errorString = NULL, DbgTypedValue contextTypedValue = DbgTypedValue()); String MaybeQuoteFormatInfoParam(const StringImpl& str); void DbgVisFailed(DebugVisualizerEntry* debugVis, const StringImpl& evalString, const StringImpl& errors); DbgTypedValue EvaluateInContext(DbgCompileUnit* dbgCompileUnit, const DbgTypedValue& contextTypedValue, const StringImpl& subExpr, DwFormatInfo* formatInfo = NULL, String* outReferenceId = NULL, String* outErrors = NULL);