Преглед изворни кода

Added watch lock, watch stack offsets (ie: {1}, {Func^2})

Brian Fiete пре 3 година
родитељ
комит
56cc35f266

+ 8 - 0
BeefLibs/Beefy2D/src/theme/dark/DarkMenu.bf

@@ -131,6 +131,14 @@ namespace Beefy.theme.dark
                         CloseSubMenu();
                         CloseSubMenu();
                 }
                 }
             }
             }
+
+			if (mMenuItem.mTooltip != null)
+			{
+				if (DarkTooltipManager.CheckMouseover(this, 20, var mousePoint))
+				{
+					DarkTooltipManager.ShowTooltip(mMenuItem.mTooltip, this, mWidth + GS!(8), GS!(-8));
+				}
+			}
         }
         }
 
 
         public override void Submit()
         public override void Submit()

+ 1 - 0
BeefLibs/Beefy2D/src/widgets/Menu.bf

@@ -564,6 +564,7 @@ namespace Beefy.widgets
     {
     {
         public Menu mParent;
         public Menu mParent;
         public String mLabel ~ delete _;
         public String mLabel ~ delete _;
+		public String mTooltip ~ delete _;
         public List<Menu> mItems = new List<Menu>() ~ DeleteContainerAndItems!(_);
         public List<Menu> mItems = new List<Menu>() ~ DeleteContainerAndItems!(_);
         
         
         public Event<delegate void(Menu menu)> mOnMenuItemSelected ~ _.Dispose();
         public Event<delegate void(Menu menu)> mOnMenuItemSelected ~ _.Dispose();

+ 12 - 0
IDE/src/Debugger/DebugManager.bf

@@ -268,6 +268,9 @@ namespace IDE.Debugger
 		[CallingConvention(.Stdcall),CLink]
 		[CallingConvention(.Stdcall),CLink]
 		static extern char8* CallStack_GetStackFrameInfo(int32 stackFrameIdx, out int addr, out char8* outFile, out int32 hotIdx, out int32 defLineStart, out int32 defLineEnd, out int32 outLine, out int32 outColumn, out int32 outLanguage, out int32 outStackSize, out FrameFlags flags);
 		static extern char8* CallStack_GetStackFrameInfo(int32 stackFrameIdx, out int addr, out char8* outFile, out int32 hotIdx, out int32 defLineStart, out int32 defLineEnd, out int32 outLine, out int32 outColumn, out int32 outLanguage, out int32 outStackSize, out FrameFlags flags);
 
 
+		[CallingConvention(.Stdcall),CLink]
+		static extern char8* CallStack_GetStackFrameId(int32 stackFrameIdx);
+
 		[CallingConvention(.Stdcall),CLink]
 		[CallingConvention(.Stdcall),CLink]
 		static extern char8* Callstack_GetStackFrameOldFileInfo(int32 stackFrameIdx);
 		static extern char8* Callstack_GetStackFrameOldFileInfo(int32 stackFrameIdx);
 
 
@@ -1256,5 +1259,14 @@ namespace IDE.Debugger
 			outText.Append(str);
 			outText.Append(str);
 			return true;
 			return true;
 		}
 		}
+
+		public bool GetStackFrameId(int32 callStackIdx, String outString)
+		{
+			char8* stackId = CallStack_GetStackFrameId(callStackIdx);
+			if (stackId == null)
+				return false;
+			outString.Append(stackId);
+			return true;
+		}
 	}
 	}
 }
 }

+ 153 - 16
IDE/src/ui/WatchPanel.bf

@@ -11,6 +11,7 @@ using Beefy.theme.dark;
 using Beefy.events;
 using Beefy.events;
 using Beefy.utils;
 using Beefy.utils;
 using IDE.Debugger;
 using IDE.Debugger;
+using Beefy.geom;
 
 
 namespace IDE.ui
 namespace IDE.ui
 {
 {
@@ -40,6 +41,8 @@ namespace IDE.ui
 		public DebugManager.Language mLanguage = .NotSet;
 		public DebugManager.Language mLanguage = .NotSet;
 
 
         public String mName ~ delete _;
         public String mName ~ delete _;
+		public String mStackFrameId ~ delete _;
+		public bool mWantsStackFrameId;
         public String mEvalStr ~ delete _;
         public String mEvalStr ~ delete _;
         public bool mCanEdit;
         public bool mCanEdit;
         public String mEditInitialize ~ delete _;
         public String mEditInitialize ~ delete _;
@@ -47,6 +50,8 @@ namespace IDE.ui
         public bool mHasValue;
         public bool mHasValue;
         public bool mIsNewExpression;
         public bool mIsNewExpression;
 		public bool mIsPending;
 		public bool mIsPending;
+		public bool mUsedLock;
+		public int32 mCurStackIdx;
 		public int mMemoryBreakpointAddr;
 		public int mMemoryBreakpointAddr;
         public int32 mHadStepCount;
         public int32 mHadStepCount;
 		public String mStringView ~ delete _;
 		public String mStringView ~ delete _;
@@ -512,21 +517,6 @@ namespace IDE.ui
                 DarkTooltipManager.CloseTooltip();
                 DarkTooltipManager.CloseTooltip();
         }
         }
 
 
-		/*public override void RecalcSize()
-		{
-			base.RecalcSize();
-			if (mWatchStringEdit.mMoreButton != null)
-				mHeight += GS!(32);
-		}*/
-
-		public override void GetTextData()
-		{
-			
-			base.GetTextData();
-
-			
-		}
-
 		public override void CheckLineCoords()
 		public override void CheckLineCoords()
 		{
 		{
 			bool changed = (mLineCoordTextVersionId != mData.mCurTextVersionId);
 			bool changed = (mLineCoordTextVersionId != mData.mCurTextVersionId);
@@ -1325,6 +1315,28 @@ namespace IDE.ui
                     }
                     }
                 }
                 }
             }
             }
+
+			if (mColumnIdx == 1)
+			{
+				var headItem = GetSubItem(0) as WatchListViewItem;
+				if (headItem.mWatchEntry?.mStackFrameId != null)
+				{
+					float drawX = mWidth - GS!(16);
+					if (headItem.mWatchRefreshButton != null)
+						drawX -= GS!(16);
+
+					uint32 color = Color.White;
+					if (headItem.mDisabled)
+					    color = 0x80FFFFFF;
+					else if (mFailed)
+					    color = 0xFFFF4040;
+					else if (headItem.mWatchEntry.mUsedLock)
+						color = 0xFFE39C39;
+
+					using (g.PushColor(color))
+						g.Draw(DarkTheme.sDarkTheme.GetImage(.LockIcon), drawX, GS!(-1));
+				}
+			}
             
             
             base.DrawAll(g);
             base.DrawAll(g);
         }
         }
@@ -1757,6 +1769,34 @@ namespace IDE.ui
                 }
                 }
             }
             }
 
 
+			if (mColumnIdx == 1)
+			{
+				var nameItem = GetSubItem(0) as WatchListViewItem;
+				if (nameItem.mWatchEntry?.mStackFrameId != null)
+				{
+					if (DarkTooltipManager.CheckMouseover(this, 20, var mousePoint))
+					{
+						float drawX = mWidth - GS!(16);
+						if (nameItem.mWatchRefreshButton != null)
+							drawX -= GS!(16);
+
+						if (Rect(drawX, 0, GS!(16), GS!(20)).Contains(mousePoint))
+						{
+							String tooltip = scope String();
+							tooltip.Append(nameItem.mWatchEntry.mStackFrameId);
+
+							int lastColon = nameItem.mWatchEntry.mStackFrameId.LastIndexOf(':');
+							if ((lastColon > -1) && (var addr = int64.Parse(nameItem.mWatchEntry.mStackFrameId.Substring(lastColon + 1), .HexNumber)))
+							{
+								tooltip.Append("\n");
+								gApp.mDebugger.GetAddressSymbolName(addr, true, tooltip);
+							}
+							DarkTooltipManager.ShowTooltip(tooltip, this, mousePoint.x, mousePoint.y);
+						}	
+					}
+				}
+			}
+
             base.Update();
             base.Update();
         }
         }
 
 
@@ -2428,7 +2468,14 @@ namespace IDE.ui
 			}
 			}
             else if (watch.mEvalStr.Length > 0)
             else if (watch.mEvalStr.Length > 0)
             {
             {
-                String evalStr = scope String(watch.mEvalStr);
+                String evalStr = scope String(1024);
+				if (watch.mStackFrameId != null)
+				{
+					evalStr.Append("{");
+					evalStr.Append(watch.mStackFrameId);
+					evalStr.Append("}");
+				}
+				evalStr.Append(watch.mEvalStr);
                 if ((watch.mReferenceId != null) && (watch.mReferenceId.StartsWith("0", StringComparison.Ordinal)))
                 if ((watch.mReferenceId != null) && (watch.mReferenceId.StartsWith("0", StringComparison.Ordinal)))
                     evalStr.Append(",refid=", watch.mReferenceId);
                     evalStr.Append(",refid=", watch.mReferenceId);
                 //gApp.DebugEvaluate(watch.mResultTypeStr, evalStr, val, -1, watch.mIsNewExpression, watch.mIsNewExpression);
                 //gApp.DebugEvaluate(watch.mResultTypeStr, evalStr, val, -1, watch.mIsNewExpression, watch.mIsNewExpression);
@@ -2478,6 +2525,13 @@ namespace IDE.ui
                     listViewItem.mErrorStart = int32.Parse(scope String(errorVals[0]));
                     listViewItem.mErrorStart = int32.Parse(scope String(errorVals[0]));
                     listViewItem.mErrorEnd = listViewItem.mErrorStart + int32.Parse(scope String(errorVals[1])).Get();
                     listViewItem.mErrorEnd = listViewItem.mErrorStart + int32.Parse(scope String(errorVals[1])).Get();
                     valueSubItem.Label = errorVals[2];
                     valueSubItem.Label = errorVals[2];
+
+					if (watch.mStackFrameId != null)
+					{
+						int32 idPrefixLen = (.)watch.mStackFrameId.Length + 2;
+						listViewItem.mErrorStart -= idPrefixLen;
+						listViewItem.mErrorEnd -= idPrefixLen;
+					}
                 }
                 }
                 else
                 else
                     valueSubItem.Label = errorVals[0];
                     valueSubItem.Label = errorVals[0];
@@ -2518,6 +2572,8 @@ namespace IDE.ui
             watch.mIsDeleted = false;
             watch.mIsDeleted = false;
             watch.mIsAppendAlloc = false;
             watch.mIsAppendAlloc = false;
             watch.mIsStackAlloc = false;
             watch.mIsStackAlloc = false;
+			watch.mUsedLock = false;
+			watch.mCurStackIdx = -1;
 			watch.mLanguage = .NotSet;
 			watch.mLanguage = .NotSet;
             DeleteAndNullify!(watch.mEditInitialize);
             DeleteAndNullify!(watch.mEditInitialize);
 			DeleteAndNullify!(watch.mAction);
 			DeleteAndNullify!(watch.mAction);
@@ -2699,6 +2755,15 @@ namespace IDE.ui
 						if (memberVals.Count > 1)
 						if (memberVals.Count > 1)
 							watch.mStringView = memberVals[1].Unescape(.. new .());
 							watch.mStringView = memberVals[1].Unescape(.. new .());
 					}
 					}
+					else if (memberVals0 == ":usedLock")
+					{
+						watch.mUsedLock = true;
+					}
+					else if (memberVals0 == ":stackIdx")
+					{
+						if (int32 stackIdx = int32.Parse(memberVals[1]))
+							watch.mCurStackIdx = stackIdx;
+					}
 					else
 					else
                         watch.ParseCmd(memberVals);
                         watch.ParseCmd(memberVals);
                     continue;
                     continue;
@@ -2739,6 +2804,14 @@ namespace IDE.ui
                 }
                 }
             }
             }
 
 
+			if (watch.mWantsStackFrameId)
+			{
+				watch.mWantsStackFrameId = false;
+				watch.mStackFrameId = gApp.mDebugger.GetStackFrameId((watch.mCurStackIdx != -1) ? watch.mCurStackIdx : gApp.mDebugger.mActiveCallStackIdx, .. new .());
+				if (gApp.mDebugger.mActiveCallStackIdx != watch.mCurStackIdx)
+					watch.mUsedLock = true;
+			}
+
             if ((watch.mReferenceId == null) && (watch.mEvalStr.Length > 0) && (!valueSubItem.mFailed))
             if ((watch.mReferenceId == null) && (watch.mEvalStr.Length > 0) && (!valueSubItem.mFailed))
             {
             {
                 // Allocate a referenceId if we didn't get one (was a temporary expression)
                 // Allocate a referenceId if we didn't get one (was a temporary expression)
@@ -2988,6 +3061,16 @@ namespace IDE.ui
             return true;
             return true;
         }
         }
 
 
+		protected static void WithSelectedWatchEntries(WatchListView listView, delegate void(WatchEntry) dlg)
+		{
+			listView.GetRoot().WithSelectedItems(scope (item) =>
+				{
+					var watchListViewItem = item as WatchListViewItem;
+					if (watchListViewItem.mWatchEntry != null)
+						dlg(watchListViewItem.mWatchEntry);
+				});
+		}
+
 		public static void ShowRightClickMenu(WatchPanel watchPanel, WatchListView listView, WatchListViewItem listViewItem, float x, float y)
 		public static void ShowRightClickMenu(WatchPanel watchPanel, WatchListView listView, WatchListViewItem listViewItem, float x, float y)
 		{
 		{
 			if (watchPanel != null)
 			if (watchPanel != null)
@@ -3039,6 +3122,60 @@ namespace IDE.ui
 						AddDisplayTypeMenu("Series Watch Display", menu, listViewItem.mWatchEntry.mResultType, refId, true);
 						AddDisplayTypeMenu("Series Watch Display", menu, listViewItem.mWatchEntry.mResultType, refId, true);
 					}
 					}
 				}
 				}
+				
+				var lockMenu = menu.AddItem("Lock");
+				var lockUnlockedItem = lockMenu.AddItem("Unlocked");
+				lockUnlockedItem.mOnMenuItemSelected.Add(new (menu) =>
+					{
+						WithSelectedWatchEntries(listView, scope (selectedWatchEntry) =>
+							{
+								DeleteAndNullify!(selectedWatchEntry.mStackFrameId);
+							});
+						gApp.RefreshWatches();
+					});
+				var lockNewItem = lockMenu.AddItem("Current Stack Frame");
+				lockNewItem.mOnMenuItemSelected.Add(new (menu) =>
+					{
+						WithSelectedWatchEntries(listView, scope (selectedWatchEntry) =>
+							{
+								int32 callStackIdx = gApp.mDebugger.mActiveCallStackIdx;
+								if (selectedWatchEntry.mCurStackIdx != -1)
+									callStackIdx = selectedWatchEntry.mCurStackIdx;
+								DeleteAndNullify!(selectedWatchEntry.mStackFrameId);
+								selectedWatchEntry.mWantsStackFrameId = true;
+							});
+						
+						gApp.RefreshWatches();
+					});
+				if (watchEntry.mStackFrameId != null)
+				{
+					var lockCurItem = lockMenu.AddItem(watchEntry.mStackFrameId);
+					lockCurItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);
+
+					int lastColon = watchEntry.mStackFrameId.LastIndexOf(':');
+					if ((lastColon > -1) && (var addr = int64.Parse(watchEntry.mStackFrameId.Substring(lastColon + 1), .HexNumber)))
+					{
+						lockCurItem.mTooltip = gApp.mDebugger.GetAddressSymbolName(addr, true, .. new .());
+						if (lockCurItem.mTooltip.IsEmpty)
+							DeleteAndNullify!(lockCurItem.mTooltip);
+					}
+
+					String stackFrameId = new String(watchEntry.mStackFrameId);
+					lockCurItem.mOnMenuItemSelected.Add(new (menu) =>
+						{
+							WithSelectedWatchEntries(listView, scope (selectedWatchEntry) =>
+								{
+									DeleteAndNullify!(selectedWatchEntry.mStackFrameId);
+									selectedWatchEntry.mStackFrameId = new .(stackFrameId);
+								});
+							gApp.RefreshWatches();
+						}
+						~ delete stackFrameId);
+				}
+				else
+				{
+					lockUnlockedItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);
+				}
 
 
 				anItem = menu.AddItem("Add Watch");
 				anItem = menu.AddItem("Add Watch");
 				anItem.mOnMenuItemSelected.Add(new (menu) =>
 				anItem.mOnMenuItemSelected.Add(new (menu) =>

+ 108 - 5
IDEHelper/DbgExprEvaluator.cpp

@@ -761,8 +761,9 @@ DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModul
 	mBlockedSideEffects = false;
 	mBlockedSideEffects = false;
 	mReferenceId = NULL;
 	mReferenceId = NULL;
 	mIsComplexExpression = false;
 	mIsComplexExpression = false;
-	mHadMemberReference = false;		
+	mHadMemberReference = false;
 	mCreatedPendingCall = false;
 	mCreatedPendingCall = false;
+	mStackSearch = NULL;
 	mValidateOnly = false;
 	mValidateOnly = false;
 	mReceivingValue = NULL;
 	mReceivingValue = NULL;
 	mCallResults = NULL;
 	mCallResults = NULL;
@@ -770,11 +771,12 @@ DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModul
 	mCallStackPreservePos = 0;
 	mCallStackPreservePos = 0;
 	mPropGet = NULL;
 	mPropGet = NULL;
 	mPropSet = NULL;
 	mPropSet = NULL;
-	mPropSrc = NULL;	
+	mPropSrc = NULL;
 }
 }
 
 
 DbgExprEvaluator::~DbgExprEvaluator()
 DbgExprEvaluator::~DbgExprEvaluator()
 {	
 {	
+	delete mStackSearch;
 }
 }
 
 
 DbgTypedValue DbgExprEvaluator::GetInt(int value)
 DbgTypedValue DbgExprEvaluator::GetInt(int value)
@@ -2526,6 +2528,15 @@ bool DbgExprEvaluator::HasField(DbgType* curCheckType, const StringImpl& fieldNa
 
 
 DbgTypedValue DbgExprEvaluator::DoLookupField(BfAstNode* targetSrc, DbgTypedValue target, DbgType* curCheckType, const StringImpl& fieldName, CPUStackFrame* stackFrame, bool allowImplicitThis)
 DbgTypedValue DbgExprEvaluator::DoLookupField(BfAstNode* targetSrc, DbgTypedValue target, DbgType* curCheckType, const StringImpl& fieldName, CPUStackFrame* stackFrame, bool allowImplicitThis)
 {	
 {	
+	if (mStackSearch != NULL)
+	{
+		if (mStackSearch->mIdentifier == targetSrc)
+		{
+			if (!mStackSearch->mSearchedTypes.Add(curCheckType))
+				return DbgTypedValue();
+		}
+	}
+
 	bool wantsStatic = (!target) || (target.mHasNoValue);
 	bool wantsStatic = (!target) || (target.mHasNoValue);
 	auto flavor = GetFlavor();
 	auto flavor = GetFlavor();
 	auto language = GetLanguage();
 	auto language = GetLanguage();
@@ -3548,7 +3559,7 @@ void DbgExprEvaluator::AutocompleteAddTopLevelTypes(const StringImpl& filter)
 	}*/
 	}*/
 }
 }
 
 
-DbgTypedValue DbgExprEvaluator::LookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError, bool* hadError)
+DbgTypedValue DbgExprEvaluator::DoLookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError, bool* hadError)
 {			
 {			
 	if (!mDebugger->mIsRunning)
 	if (!mDebugger->mIsRunning)
 		return DbgTypedValue();
 		return DbgTypedValue();
@@ -3963,6 +3974,92 @@ DbgTypedValue DbgExprEvaluator::LookupIdentifier(BfAstNode* identifierNode, bool
 	return DbgTypedValue();
 	return DbgTypedValue();
 }
 }
 
 
+DbgTypedValue DbgExprEvaluator::LookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError, bool* hadError)
+{
+	if ((mStackSearch != NULL) && (mStackSearch->mIdentifier == NULL))
+	{		
+		mStackSearch->mIdentifier = identifierNode;
+		mStackSearch->mStartingStackIdx = mCallStackIdx;
+
+		int skipCount = 0;
+
+		StringT<256> findStr;
+		for (int i = 0; i < mStackSearch->mSearchStr.mLength; i++)
+		{			
+			char c = mStackSearch->mSearchStr[i];
+
+			if (c == '^')
+			{
+				skipCount = atoi(mStackSearch->mSearchStr.c_str() + i + 1);
+				break;
+			}
+
+			if (c == '.')
+			{
+				findStr += ':';
+				findStr += ':';
+			}
+			else
+				findStr += c;
+		}
+
+		while (true)
+		{
+			auto stackFrame = GetStackFrame();
+			bool matches = true;
+
+			if (mStackSearch->mSearchStr != "*")
+			{
+				mDebugger->UpdateCallStackMethod(mCallStackIdx);
+				if (stackFrame->mSubProgram != NULL)
+				{	
+					int strLen = strlen(stackFrame->mSubProgram->mName);
+					if (strLen >= findStr.mLength)
+					{
+						if (strncmp(stackFrame->mSubProgram->mName + strLen - findStr.mLength, findStr.c_str(), findStr.mLength) == 0)
+						{
+							if (strLen > findStr.mLength)
+							{
+								char endC = stackFrame->mSubProgram->mName[strLen - findStr.mLength - 1];
+								if (endC != ':')
+									matches = false;
+							}
+						}
+						else
+							matches = false;
+					}
+					else
+						matches = false;
+				}
+				else
+					matches = false;
+			}
+
+			if (matches)
+			{
+				if (skipCount > 0)
+				{
+					skipCount--;
+				}
+				else
+				{
+					auto result = DoLookupIdentifier(identifierNode, ignoreInitialError, hadError);
+					if (result)
+						return result;
+				}
+			}
+
+			mCallStackIdx++;
+			if (mCallStackIdx >= mDebugger->mCallStack.mSize)
+				mDebugger->UpdateCallStack();
+			if (mCallStackIdx >= mDebugger->mCallStack.mSize)
+				return DbgTypedValue();
+		}
+	}
+
+	return DoLookupIdentifier(identifierNode, ignoreInitialError, hadError);
+}
+
 void DbgExprEvaluator::Visit(BfAssignmentExpression* assignExpr)
 void DbgExprEvaluator::Visit(BfAssignmentExpression* assignExpr)
 {
 {
 	mHadSideEffects = true;
 	mHadSideEffects = true;
@@ -4295,6 +4392,12 @@ void DbgExprEvaluator::AutocompleteAddMethod(const char* methodName, const Strin
 
 
 void DbgExprEvaluator::AutocompleteAddMembers(DbgType* dbgType, bool wantsStatic, bool wantsNonStatic, const StringImpl& filter, bool isCapture)
 void DbgExprEvaluator::AutocompleteAddMembers(DbgType* dbgType, bool wantsStatic, bool wantsNonStatic, const StringImpl& filter, bool isCapture)
 {
 {
+	if (mStackSearch != NULL)
+	{
+		if (!mStackSearch->mAutocompleteSearchedTypes.Add(dbgType))
+			return;
+	}
+
 	DbgLanguage language = GetLanguage();
 	DbgLanguage language = GetLanguage();
 	DbgFlavor flavor = GetFlavor();
 	DbgFlavor flavor = GetFlavor();
 	if ((mDbgCompileUnit != NULL) && (dbgType->mLanguage != DbgLanguage_Unknown) && (dbgType->mLanguage != language))
 	if ((mDbgCompileUnit != NULL) && (dbgType->mLanguage != DbgLanguage_Unknown) && (dbgType->mLanguage != language))
@@ -7609,7 +7712,7 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue
 			}
 			}
 			else if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
 			else if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
 			{
 			{
-				demangledName = BfDemangler::Demangle(symbolName, DbgLanguage_Beef);
+				demangledName = BfDemangler::Demangle(symbolName, GetLanguage());
 			}
 			}
 			else
 			else
 			{
 			{
@@ -7634,7 +7737,7 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue
 			DbgModule* dwarf;
 			DbgModule* dwarf;
 			if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
 			if (mDebugTarget->FindSymbolAt(funcPtr, &symbolName, &offset, &dwarf))
 			{
 			{
-				String firstParamType = BfDemangler::Demangle(symbolName, DbgLanguage_Beef, BfDemangler::Flag_CaptureTargetType);
+				String firstParamType = BfDemangler::Demangle(symbolName, GetLanguage(), BfDemangler::Flag_CaptureTargetType);
 				auto targetType = mDbgModule->FindType(firstParamType, NULL, DbgLanguage_BeefUnfixed);
 				auto targetType = mDbgModule->FindType(firstParamType, NULL, DbgLanguage_BeefUnfixed);
 				if (targetType)
 				if (targetType)
 				{
 				{

+ 21 - 1
IDEHelper/DbgExprEvaluator.h

@@ -194,6 +194,7 @@ struct DwFormatInfo
 	bool mRawString;
 	bool mRawString;
 	bool mAllowStringView;
 	bool mAllowStringView;
 	bool mNoEdit;
 	bool mNoEdit;
+	String mStackSearchStr;
 	DbgTypeKindFlags mTypeKindFlags;
 	DbgTypeKindFlags mTypeKindFlags;
 	intptr mArrayLength;
 	intptr mArrayLength;
 	intptr mOverrideCount;
 	intptr mOverrideCount;
@@ -283,6 +284,23 @@ public:
 	Array<uint8> mSRetData;
 	Array<uint8> mSRetData;
 };
 };
 
 
+class DbgStackSearch
+{
+public:
+	String mSearchStr;
+	BfAstNode* mIdentifier;
+	HashSet<DbgType*> mSearchedTypes;
+	HashSet<DbgType*> mAutocompleteSearchedTypes;
+	int mStartingStackIdx;
+
+public:
+	DbgStackSearch()
+	{
+		mIdentifier = NULL;
+		mStartingStackIdx = -1;
+	}
+};
+
 class DbgExprEvaluator : public BfStructuralVisitor
 class DbgExprEvaluator : public BfStructuralVisitor
 {
 {
 public:
 public:
@@ -351,11 +369,12 @@ public:
 	bool mBlockedSideEffects;	
 	bool mBlockedSideEffects;	
 	bool mIgnoreErrors;
 	bool mIgnoreErrors;
 	bool mCreatedPendingCall;
 	bool mCreatedPendingCall;
-	bool mValidateOnly;
+	bool mValidateOnly;	
 	int mCallStackIdx;
 	int mCallStackIdx;
 	int mCursorPos;	
 	int mCursorPos;	
 
 
 	DwAutoComplete* mAutoComplete;
 	DwAutoComplete* mAutoComplete;
+	DbgStackSearch* mStackSearch;
 
 
 	Array<Array<uint8>> mTempStorage;
 	Array<Array<uint8>> mTempStorage;
 	Array<NodeReplaceRecord> mDeferredInsertExplicitThisVector;
 	Array<NodeReplaceRecord> mDeferredInsertExplicitThisVector;
@@ -431,6 +450,7 @@ public:
 	bool HasField(DbgType* type, const StringImpl& fieldName);
 	bool HasField(DbgType* type, const StringImpl& fieldName);
 	DbgTypedValue DoLookupField(BfAstNode* targetSrc, DbgTypedValue target, DbgType* curCheckType, const StringImpl& fieldName, CPUStackFrame* stackFrame, bool allowImplicitThis);	
 	DbgTypedValue DoLookupField(BfAstNode* targetSrc, DbgTypedValue target, DbgType* curCheckType, const StringImpl& fieldName, CPUStackFrame* stackFrame, bool allowImplicitThis);	
 	DbgTypedValue LookupField(BfAstNode* targetSrc, DbgTypedValue target, const StringImpl& fieldName);	
 	DbgTypedValue LookupField(BfAstNode* targetSrc, DbgTypedValue target, const StringImpl& fieldName);	
+	DbgTypedValue DoLookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError, bool* hadError);
 	DbgTypedValue LookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL);
 	DbgTypedValue LookupIdentifier(BfAstNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL);
 	void LookupSplatMember(const DbgTypedValue& target, const StringImpl& fieldName);
 	void LookupSplatMember(const DbgTypedValue& target, const StringImpl& fieldName);
 	void LookupSplatMember(BfAstNode* srcNode, BfAstNode* lookupNode, const DbgTypedValue& target, const StringImpl& fieldName, String* outFindName = NULL, bool* outIsConst = NULL, StringImpl* forceName = NULL);
 	void LookupSplatMember(BfAstNode* srcNode, BfAstNode* lookupNode, const DbgTypedValue& target, const StringImpl& fieldName, String* outFindName = NULL, bool* outIsConst = NULL, StringImpl* forceName = NULL);

+ 7 - 0
IDEHelper/DebugManager.cpp

@@ -1403,6 +1403,13 @@ BF_EXPORT const char* BF_CALLTYPE CallStack_GetStackFrameInfo(int stackFrameIdx,
 	return outString.c_str();
 	return outString.c_str();
 }
 }
 
 
+BF_EXPORT const char* BF_CALLTYPE CallStack_GetStackFrameId(int stackFrameIdx)
+{
+	String& outString = *gTLStrReturn.Get();
+	outString = gDebugger->GetStackFrameId(stackFrameIdx);
+	return outString.c_str();
+}
+
 BF_EXPORT const char* BF_CALLTYPE Callstack_GetStackFrameOldFileInfo(int stackFrameIdx)
 BF_EXPORT const char* BF_CALLTYPE Callstack_GetStackFrameOldFileInfo(int stackFrameIdx)
 {
 {
 	String& outString = *gTLStrReturn.Get();
 	String& outString = *gTLStrReturn.Get();

+ 1 - 0
IDEHelper/Debugger.h

@@ -329,6 +329,7 @@ public:
 	virtual void GetCodeAddrInfo(intptr addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn) = 0;
 	virtual void GetCodeAddrInfo(intptr addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn) = 0;
 	virtual void GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx) = 0;
 	virtual void GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx) = 0;
 	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) = 0;
 	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) = 0;
+	virtual String GetStackFrameId(int stackFrameIdx) { return ""; }
 	virtual String Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) = 0;
 	virtual String Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) = 0;
 	virtual int GetJmpState(int stackFrameIdx) = 0;
 	virtual int GetJmpState(int stackFrameIdx) = 0;
 	virtual intptr GetStackFrameCalleeAddr(int stackFrameIdx) = 0;
 	virtual intptr GetStackFrameCalleeAddr(int stackFrameIdx) = 0;

+ 244 - 13
IDEHelper/WinDebugger.cpp

@@ -6371,12 +6371,7 @@ String WinDebugger::ReadString(DbgTypeCode charType, intptr addr, bool isLocalAd
 	bool wasTerminated = false;
 	bool wasTerminated = false;
 	String valString;	
 	String valString;	
 	intptr maxShowSize = 255;
 	intptr maxShowSize = 255;
-
-	if (wantStringView)
-	{
-		NOP;
-	}
-
+	
 	if (maxLength == -1)
 	if (maxLength == -1)
 		maxLength = formatInfo.mOverrideCount;
 		maxLength = formatInfo.mOverrideCount;
 	else if (formatInfo.mOverrideCount != -1)
 	else if (formatInfo.mOverrideCount != -1)
@@ -6771,7 +6766,7 @@ String WinDebugger::DbgTypedValueToString(const DbgTypedValue& origTypedValue, c
 			return retVal;
 			return retVal;
 		}
 		}
 	}
 	}
-
+	
 	switch (dwValueType->mTypeCode)
 	switch (dwValueType->mTypeCode)
 	{
 	{
 	case DbgType_Void:
 	case DbgType_Void:
@@ -9239,6 +9234,11 @@ String WinDebugger::EvaluateContinue(DbgPendingExpr* pendingExpr, BfPassInstance
 	}
 	}
 	
 	
 	DbgExprEvaluator dbgExprEvaluator(this, dbgModule, &bfPassInstance, pendingExpr->mCallStackIdx, pendingExpr->mCursorPos);
 	DbgExprEvaluator dbgExprEvaluator(this, dbgModule, &bfPassInstance, pendingExpr->mCallStackIdx, pendingExpr->mCursorPos);
+	if (!pendingExpr->mFormatInfo.mStackSearchStr.IsEmpty())
+	{
+		dbgExprEvaluator.mStackSearch = new DbgStackSearch();
+		dbgExprEvaluator.mStackSearch->mSearchStr = pendingExpr->mFormatInfo.mStackSearchStr;
+	}
 	dbgExprEvaluator.mLanguage = pendingExpr->mFormatInfo.mLanguage;
 	dbgExprEvaluator.mLanguage = pendingExpr->mFormatInfo.mLanguage;
 	dbgExprEvaluator.mReferenceId = &pendingExpr->mReferenceId;	
 	dbgExprEvaluator.mReferenceId = &pendingExpr->mReferenceId;	
 	dbgExprEvaluator.mExpressionFlags = pendingExpr->mExpressionFlags;	
 	dbgExprEvaluator.mExpressionFlags = pendingExpr->mExpressionFlags;	
@@ -9446,6 +9446,8 @@ String WinDebugger::EvaluateContinue(DbgPendingExpr* pendingExpr, BfPassInstance
 
 
 		if (dbgExprEvaluator.mHadSideEffects)
 		if (dbgExprEvaluator.mHadSideEffects)
 			val += "\n:sideeffects";
 			val += "\n:sideeffects";
+		if ((dbgExprEvaluator.mStackSearch != NULL) && (dbgExprEvaluator.mStackSearch->mStartingStackIdx != dbgExprEvaluator.mCallStackIdx))
+			val += StrFormat("\n:stackIdx\t%d", dbgExprEvaluator.mCallStackIdx);
 
 
 		auto underlyingType = exprResult.mType->RemoveModifiers();
 		auto underlyingType = exprResult.mType->RemoveModifiers();
 		bool canEdit = true;
 		bool canEdit = true;
@@ -9625,13 +9627,172 @@ String WinDebugger::Evaluate(const StringImpl& expr, DwFormatInfo formatInfo, in
 		formatInfo.mAllowStringView = true;
 		formatInfo.mAllowStringView = true;
 	}
 	}
 
 
+	auto terminatedExpr = expr + ";";
+
+	auto prevActiveThread = mActiveThread;
+	bool restoreActiveThread = false;
+	defer(
+		{
+			if (restoreActiveThread)
+				SetActiveThread(prevActiveThread->mThreadId);
+		});
+
+	bool usedSpecifiedLock = false;
+	int stackIdxOverride = -1;	
+
+	if (terminatedExpr.StartsWith('{'))
+	{
+		int closeIdx = terminatedExpr.IndexOf('}');
+		String locString = terminatedExpr.Substring(1, closeIdx - 1);
+
+		for (int i = 0; i <= closeIdx; i++)
+			terminatedExpr[i] = ' ';
+
+		locString.Trim();
+		if (locString.StartsWith("Thread:", StringImpl::CompareKind_OrdinalIgnoreCase))
+		{
+			bool foundLockMatch = true;
+
+			locString.Remove(0, 7);
+			char* endPtr = NULL;
+			int64 threadId = (int64)strtoll(locString.c_str(), &endPtr, 10);
+
+			if (endPtr != NULL)
+			{
+				locString.Remove(0, endPtr - locString.c_str());
+				locString.Trim();
+
+				if (locString.StartsWith("SP:", StringImpl::CompareKind_OrdinalIgnoreCase))
+				{
+					locString.Remove(0, 3);
+					char* endPtr = NULL;
+					uint64 sp = (uint64)strtoll(locString.c_str(), &endPtr, 16);
+
+					if (endPtr != NULL)
+					{
+						locString.Remove(0, endPtr - locString.c_str());
+						locString.Trim();
+
+						if (locString.StartsWith("Func:", StringImpl::CompareKind_OrdinalIgnoreCase))
+						{
+							locString.Remove(0, 5);
+							char* endPtr = NULL;
+							int64 funcAddr = (int64)strtoll(locString.c_str(), &endPtr, 16);
+							
+							if (endPtr != NULL)
+							{	
+								// Actually do it
+
+								if ((mActiveThread != NULL) && (mActiveThread->mThreadId != threadId))
+									restoreActiveThread = true;
+								if ((mActiveThread == NULL) || (mActiveThread->mThreadId != threadId))
+									SetActiveThread(threadId);
+								if ((mActiveThread != NULL) && (mActiveThread->mThreadId == threadId))
+								{
+									int foundStackIdx = -1;
+
+									int checkStackIdx = 0;
+									while (true)
+									{
+										if (checkStackIdx >= mCallStack.mSize)
+											UpdateCallStack();
+										if (checkStackIdx >= mCallStack.mSize)
+											break;
+
+										auto stackFrame = mCallStack[checkStackIdx];
+										if (stackFrame->mRegisters.GetSP() == sp)
+										{
+											foundStackIdx = checkStackIdx;
+											break;
+										}
+
+										if (stackFrame->mRegisters.GetSP() > sp)
+										{
+											foundStackIdx = checkStackIdx - 1;
+											break;											
+										}
+
+										checkStackIdx++;
+									}
+
+									if (foundStackIdx != -1)
+									{
+										UpdateCallStackMethod(foundStackIdx);
+										auto stackFrame = mCallStack[foundStackIdx];
+										
+										if ((stackFrame->mSubProgram != NULL) && ((int64)stackFrame->mSubProgram->mBlock.mLowPC == funcAddr))
+										{
+											if ((callStackIdx != foundStackIdx) || (mActiveThread != prevActiveThread))
+												usedSpecifiedLock = true;
+											callStackIdx = foundStackIdx;
+											foundLockMatch = true;
+										}
+									}
+								}								
+							}
+						}
+					}
+				}
+			}
+
+			if (!foundLockMatch)
+				return "!Locked stack frame not found";
+
+			bool doClear = false;
+			for (int i = closeIdx; i < terminatedExpr.mLength; i++)
+			{
+				char c = terminatedExpr[i];
+				if (doClear)
+				{
+					terminatedExpr[i] = ' ';
+					if (c == '}')
+						break;
+				}
+				else 
+				{
+					if (c == '{')
+					{
+						int endIdx = terminatedExpr.IndexOf('}');
+						if (endIdx == -1)
+							break;
+						terminatedExpr[i] = ' ';
+						doClear = true;
+					}
+					else if (!::isspace((uint8)c))
+						break;					
+				}
+
+			}
+		}		
+		else if (!locString.IsEmpty())
+		{			
+			const char* checkPtr = locString.c_str();
+			if ((*checkPtr == '^') || (*checkPtr == '@'))
+				checkPtr++;
+			
+			char* endPtr = NULL;
+			int useCallStackIdx = strtol(checkPtr, &endPtr, 10);
+			if (endPtr == locString.c_str() + locString.length())
+			{
+				if (locString[0] == '@')
+					callStackIdx = useCallStackIdx;
+				else
+					callStackIdx += useCallStackIdx;
+				stackIdxOverride = callStackIdx;
+			}
+			else
+			{
+				formatInfo.mStackSearchStr = locString;
+			}
+		}
+	}
+
 	auto dbgModule = GetCallStackDbgModule(callStackIdx);
 	auto dbgModule = GetCallStackDbgModule(callStackIdx);
 	auto dbgSubprogram = GetCallStackSubprogram(callStackIdx);
 	auto dbgSubprogram = GetCallStackSubprogram(callStackIdx);
 	DbgCompileUnit* dbgCompileUnit = NULL;
 	DbgCompileUnit* dbgCompileUnit = NULL;
 	if (dbgSubprogram != NULL)
 	if (dbgSubprogram != NULL)
 		dbgCompileUnit = dbgSubprogram->mCompileUnit;	
 		dbgCompileUnit = dbgSubprogram->mCompileUnit;	
-
-	auto terminatedExpr = expr + ";";
+	
 	if ((expr.length() > 0) && (expr[0] == '!'))
 	if ((expr.length() > 0) && (expr[0] == '!'))
 	{
 	{
 		if (expr.StartsWith("!step "))
 		if (expr.StartsWith("!step "))
@@ -9688,7 +9849,7 @@ String WinDebugger::Evaluate(const StringImpl& expr, DwFormatInfo formatInfo, in
 	parser->mCompatMode = true;
 	parser->mCompatMode = true;
 	
 	
 	BfPassInstance bfPassInstance(mBfSystem);	
 	BfPassInstance bfPassInstance(mBfSystem);	
-	
+		
 	if ((terminatedExpr.length() > 2) && (terminatedExpr[0] == '@'))
 	if ((terminatedExpr.length() > 2) && (terminatedExpr[0] == '@'))
 	{
 	{
 		if (terminatedExpr[1] == '!') // Return string as error
 		if (terminatedExpr[1] == '!') // Return string as error
@@ -9852,6 +10013,13 @@ String WinDebugger::Evaluate(const StringImpl& expr, DwFormatInfo formatInfo, in
 	}
 	}
 	else
 	else
 		delete pendingExpr;
 		delete pendingExpr;
+
+	if ((!formatInfo.mRawString) && (usedSpecifiedLock))
+		result += "\n:usedLock";
+
+	if ((!formatInfo.mRawString) && (stackIdxOverride != -1))
+		result += StrFormat("\n:stackIdx\t%d", stackIdxOverride);
+
 	return result;
 	return result;
 }
 }
 
 
@@ -10663,10 +10831,33 @@ void WinDebugger::SetActiveThread(int threadId)
 {	
 {	
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 	
 	
+	if ((mActiveThread != NULL) && (mActiveThread->mThreadId == threadId))
+		return;
+
+	auto prevThread = mActiveThread;
+
 	if (mThreadMap.TryGetValue(threadId, &mActiveThread))
 	if (mThreadMap.TryGetValue(threadId, &mActiveThread))
 	{
 	{
 		BfLogDbg("SetActiveThread %d\n", threadId);
 		BfLogDbg("SetActiveThread %d\n", threadId);
-		ClearCallStack();
+
+		if (prevThread != NULL)
+		{
+			Array<WdStackFrame*>* prevFrameArray = NULL;
+			mSavedCallStacks.TryAdd(prevThread, NULL, &prevFrameArray);
+			for (auto frameInfo : *prevFrameArray)
+				delete frameInfo;
+			*prevFrameArray = mCallStack;
+			mCallStack.Clear();
+		}
+		
+		DoClearCallStack(false);
+
+		Array<WdStackFrame*>* newFrameArray = NULL;
+		if (mSavedCallStacks.TryGetValue(mActiveThread, &newFrameArray))
+		{
+			mCallStack = *newFrameArray;
+			newFrameArray->Clear();
+		}
 	}
 	}
 	else
 	else
 	{
 	{
@@ -10718,8 +10909,8 @@ bool WinDebugger::IsActiveThreadWaiting()
 	return mActiveThread == mDebuggerWaitingThread;
 	return mActiveThread == mDebuggerWaitingThread;
 }
 }
 
 
-void WinDebugger::ClearCallStack()
-{	
+void WinDebugger::DoClearCallStack(bool clearSavedStacks)
+{
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 
 
 	BfLogDbg("ClearCallstack\n");
 	BfLogDbg("ClearCallstack\n");
@@ -10728,10 +10919,25 @@ void WinDebugger::ClearCallStack()
 	for (auto wdStackFrame : mCallStack)
 	for (auto wdStackFrame : mCallStack)
 		delete wdStackFrame;
 		delete wdStackFrame;
 
 
+	if (clearSavedStacks)
+	{
+		for (auto& kv : mSavedCallStacks)
+		{
+			for (auto wdStackFrame : kv.mValue)
+				delete wdStackFrame;
+		}
+		mSavedCallStacks.Clear();
+	}
+
 	mCallStack.Clear();
 	mCallStack.Clear();
 	mIsPartialCallStack = true;
 	mIsPartialCallStack = true;
 }
 }
 
 
+void WinDebugger::ClearCallStack()
+{	
+	DoClearCallStack(true);
+}
+
 void WinDebugger::UpdateCallStack(bool slowEarlyOut)
 void WinDebugger::UpdateCallStack(bool slowEarlyOut)
 {
 {
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 	AutoCrit autoCrit(mDebugManager->mCritSect);
@@ -11356,6 +11562,27 @@ String WinDebugger::GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* o
 	return outName;
 	return outName;
 }
 }
 
 
+String WinDebugger::GetStackFrameId(int stackFrameIdx)
+{
+	AutoCrit autoCrit(mDebugManager->mCritSect);
+
+	if (!FixCallStackIdx(stackFrameIdx))
+		return "";
+
+	int actualStackFrameIdx = BF_MAX(0, stackFrameIdx);
+	UpdateCallStackMethod(actualStackFrameIdx);
+	WdStackFrame* wdStackFrame = mCallStack[actualStackFrameIdx];
+
+	intptr addr = 0;
+	if (wdStackFrame->mSubProgram != NULL)
+		addr = wdStackFrame->mSubProgram->mBlock.mLowPC;
+	else
+		addr = wdStackFrame->mRegisters.GetPC();
+
+	String str = StrFormat("Thread:%d SP:%llX Func:%llX", mActiveThread->mThreadId, wdStackFrame->mRegisters.GetSP(), addr);
+	return str;
+}
+
 String WinDebugger::Callstack_GetStackFrameOldFileInfo(int stackFrameIdx)
 String WinDebugger::Callstack_GetStackFrameOldFileInfo(int stackFrameIdx)
 {
 {
 	AutoCrit autoCrit(mDebugManager->mCritSect);
 	AutoCrit autoCrit(mDebugManager->mCritSect);
@@ -11550,6 +11777,10 @@ String WinDebugger::GetAddressSourceLocation(intptr address)
 
 
 String WinDebugger::GetAddressSymbolName(intptr address, bool demangle)
 String WinDebugger::GetAddressSymbolName(intptr address, bool demangle)
 {
 {
+	auto subProgram = mDebugTarget->FindSubProgram(address);
+	if (subProgram != NULL)
+		return subProgram->ToString();	
+
 	String outSymbol;
 	String outSymbol;
 	addr_target offset = 0;
 	addr_target offset = 0;
 	DbgModule* dbgModule;
 	DbgModule* dbgModule;

+ 3 - 0
IDEHelper/WinDebugger.h

@@ -416,6 +416,7 @@ public:
 	Dictionary<addr_target, WdBreakpoint*> mBreakpointAddrMap;
 	Dictionary<addr_target, WdBreakpoint*> mBreakpointAddrMap;
 	Array<int> mFreeMemoryBreakIndices;
 	Array<int> mFreeMemoryBreakIndices;
 	Array<WdStackFrame*> mCallStack;
 	Array<WdStackFrame*> mCallStack;
+	Dictionary<WdThreadInfo*, Array<WdStackFrame*>> mSavedCallStacks;
 	bool mIsPartialCallStack;
 	bool mIsPartialCallStack;
 	int mRequestedStackFrameIdx; // -1 means to show mShowPCOverride, -2 means "auto" stop, -3 means breakpoint - normally 0 but during inlining the address can be ambiguous
 	int mRequestedStackFrameIdx; // -1 means to show mShowPCOverride, -2 means "auto" stop, -3 means breakpoint - normally 0 but during inlining the address can be ambiguous
 	int mBreakStackFrameIdx;
 	int mBreakStackFrameIdx;
@@ -560,6 +561,7 @@ public:
 	bool CheckConditionalBreakpoint(WdBreakpoint* breakpoint, DbgSubprogram* dbgSubprogram, addr_target pcAddress);
 	bool CheckConditionalBreakpoint(WdBreakpoint* breakpoint, DbgSubprogram* dbgSubprogram, addr_target pcAddress);
 	void CleanupDebugEval(bool restoreRegisters = true);
 	void CleanupDebugEval(bool restoreRegisters = true);
 	bool FixCallStackIdx(int& callStackIdx);	
 	bool FixCallStackIdx(int& callStackIdx);	
+	void DoClearCallStack(bool clearSavedStacks);
 	
 	
 	int LoadDebugInfoForModule(DbgModule* dbgModule);	
 	int LoadDebugInfoForModule(DbgModule* dbgModule);	
 
 
@@ -631,6 +633,7 @@ public:
 	virtual void GetCodeAddrInfo(intptr addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn) 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 void GetStackAllocInfo(intptr addr, int* outThreadId, int* outStackIdx) override;
 	virtual String GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn, int* outLanguage, int* outStackSize, int8* outFlags) override;
 	virtual String GetStackFrameInfo(int stackFrameIdx, intptr* addr, String* outFile, int* outHotIdx, int* outDefLineStart, int* outDefLineEnd, int* outLine, int* outColumn, int* outLanguage, int* outStackSize, int8* outFlags) override;
+	virtual String GetStackFrameId(int stackFrameIdx) override;
 	virtual String Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) override;
 	virtual String Callstack_GetStackFrameOldFileInfo(int stackFrameIdx) override;
 	virtual int GetJmpState(int stackFrameIdx) override;
 	virtual int GetJmpState(int stackFrameIdx) override;
 	virtual intptr GetStackFrameCalleeAddr(int stackFrameIdx) override;
 	virtual intptr GetStackFrameCalleeAddr(int stackFrameIdx) override;