From 33aa0ff004ad712667baafa7dcd2414e417e8147 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Wed, 17 Nov 2021 11:18:23 -0800 Subject: [PATCH] Add operand highlighting When a code or data line is selected in the code list, if the operand is an address inside the file, we highlight the address and label. It's also useful to highlight the other way: when a code or data line is selected, find all lines whose operands reference it, and highlight the operand field. This is a little trickier because there can be multiple references, but all of the information we need is in the cross-reference table. --- PluginCommon/VisBitmap8.cs | 2 + SourceGen/DisplayList.cs | 20 +++++++- SourceGen/MainController.cs | 66 +++++++++++++++++++++---- SourceGen/WpfGui/CodeListItemStyle.xaml | 18 +++++++ SourceGen/WpfGui/MainWindow.xaml | 2 +- SourceGen/WpfGui/MainWindow.xaml.cs | 32 ++++++++++-- 6 files changed, 123 insertions(+), 17 deletions(-) diff --git a/PluginCommon/VisBitmap8.cs b/PluginCommon/VisBitmap8.cs index 6de27d0..ca738ef 100644 --- a/PluginCommon/VisBitmap8.cs +++ b/PluginCommon/VisBitmap8.cs @@ -55,6 +55,8 @@ namespace PluginCommon { mNextColorIdx = 0; } + // TODO: add GetPixelIndex, which returns the index we passed into SetPixelIndex + public int GetPixel(int x, int y) { byte pix = mData[x + y * Width]; return mPalette[pix]; diff --git a/SourceGen/DisplayList.cs b/SourceGen/DisplayList.cs index 13c6762..699e3f3 100644 --- a/SourceGen/DisplayList.cs +++ b/SourceGen/DisplayList.cs @@ -369,6 +369,10 @@ namespace SourceGen { // examined by a data trigger in CodeListItemStyle.xaml. public bool HasAddrLabelHighlight { get; private set; } + // Set to true if we want to highlight the operand field. This is + // examined by a data trigger in CodeListItemStyle.xaml. + public bool HasOperandHighlight { get; private set; } + // Set to true if the Flags field has been modified. public bool HasModifiedFlags { get { return (mPartFlags & PartFlags.HasModifiedFlags) != 0; } @@ -502,18 +506,30 @@ namespace SourceGen { return parts; } - public static FormattedParts AddSelectionHighlight(FormattedParts orig) { + public static FormattedParts AddSelectionAddrHighlight(FormattedParts orig) { FormattedParts newParts = Clone(orig); newParts.HasAddrLabelHighlight = true; return newParts; } - public static FormattedParts RemoveSelectionHighlight(FormattedParts orig) { + public static FormattedParts RemoveSelectionAddrHighlight(FormattedParts orig) { FormattedParts newParts = Clone(orig); newParts.HasAddrLabelHighlight = false; return newParts; } + public static FormattedParts AddSelectionOperHighlight(FormattedParts orig) { + FormattedParts newParts = Clone(orig); + newParts.HasOperandHighlight = true; + return newParts; + } + + public static FormattedParts RemoveSelectionOperHighlight(FormattedParts orig) { + FormattedParts newParts = Clone(orig); + newParts.HasOperandHighlight = false; + return newParts; + } + public override string ToString() { return "[Parts: index=" + ListIndex + " off=" + Offset + "]"; } diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 0cd1787..5a24a13 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -181,6 +181,11 @@ namespace SourceGen { /// private int mTargetHighlightIndex = -1; + /// + /// Tracks the operands we have highlighted. + /// + private List mOperandHighlights = new List(); + /// /// Code list color scheme. /// @@ -879,8 +884,20 @@ namespace SourceGen { CodeLineList, mMainWin.CodeDisplayList.SelectedIndices, topItemIndex); //savedSel.DebugDump(); - // Clear this so we don't try to fiddle with it later. + // Clear the addr/label highlight index. + // (Certain changes will blow away the CodeDisplayList and affect the selection, + // which will cause the selection-changed handler to try to un-highlight something + // that doesn't exist. We want to clear the index here, but we probably also want + // to clear the highlighting before we do it. As it happens, changes will either + // be big enough to wipe out our highlight, or small enough that we immediately + // re-highlight the thing that's already highlighted, so it doesn't really matter. + // If we start to see vestigial highlighting after a change, we'll need to be + // more rigorous here.) mTargetHighlightIndex = -1; + + // Clear operand highlighting indices as well. + mOperandHighlights.Clear(); + mReanalysisTimer.EndTask("Save selection"); mReanalysisTimer.StartTask("Apply changes"); @@ -1404,7 +1421,11 @@ namespace SourceGen { } mDataPathName = null; mProjectPathName = null; + + // We may get a "selection changed" message as things are being torn down. Clear + // these so we don't try to remove the highlight from something that doesn't exist. mTargetHighlightIndex = -1; + mOperandHighlights.Clear(); mMainWin.ShowCodeListView = false; mMainWin.ProjectClosing(); @@ -3405,16 +3426,19 @@ namespace SourceGen { private bool mUpdatingSelectionHighlight; // recursion guard for next method /// - /// Updates the selection highlight. When a code item with an operand offset is + /// Updates the selection highlights. When a code or data item with an operand offset is /// selected, such as a branch, we want to highlight the address and label of the - /// target. + /// target. When a code or data item is referenced by another instruction, such as a + /// branch, we want to highlight the operands of all such instructions. /// private void UpdateSelectionHighlight() { if (mUpdatingSelectionHighlight) { return; } + mUpdatingSelectionHighlight = true; - int targetIndex = FindSelectionHighlight(); + int targetIndex = FindSelectionAddrHighlight(out bool isSingleCodeData, + out int selIndex); if (mTargetHighlightIndex != targetIndex) { Debug.WriteLine("Target highlight moving from " + mTargetHighlightIndex + " to " + targetIndex); @@ -3429,25 +3453,47 @@ namespace SourceGen { // it will be the selected line while we're doing this little dance. When the // calls below update the selection, this method will be called again. This // turns into infinite recursion. - mUpdatingSelectionHighlight = true; - mMainWin.CodeListView_RemoveSelectionHighlight(mTargetHighlightIndex); - mMainWin.CodeListView_AddSelectionHighlight(targetIndex); - mUpdatingSelectionHighlight = false; + mMainWin.CodeListView_RemoveSelectionAddrHighlight(mTargetHighlightIndex); + mMainWin.CodeListView_AddSelectionAddrHighlight(targetIndex); mTargetHighlightIndex = targetIndex; } + + if (mOperandHighlights.Count > 0) { + foreach (int index in mOperandHighlights) { + mMainWin.CodeListView_RemoveSelectionOperHighlight(index); + } + mOperandHighlights.Clear(); + } + if (isSingleCodeData) { + LineListGen.Line line = CodeLineList[selIndex]; + XrefSet xrefs = mProject.GetXrefSet(line.FileOffset); + if (xrefs != null) { + foreach (XrefSet.Xref xr in xrefs) { + int refIndex = CodeLineList.FindCodeDataIndexByOffset(xr.Offset); + mMainWin.CodeListView_AddSelectionOperHighlight(refIndex); + mOperandHighlights.Add(refIndex); + } + } + } + + mUpdatingSelectionHighlight = false; } - private int FindSelectionHighlight() { + private int FindSelectionAddrHighlight(out bool isSingleCodeData, out int selIndex) { if (mMainWin.CodeListView_GetSelectionCount() != 1) { + isSingleCodeData = false; + selIndex = -1; return -1; } - int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex(); + selIndex = mMainWin.CodeListView_GetFirstSelectedIndex(); LineListGen.Line line = CodeLineList[selIndex]; if (!line.IsCodeOrData) { + isSingleCodeData = false; return -1; } Debug.Assert(line.FileOffset >= 0); + isSingleCodeData = true; // Does this have an operand with an in-file target offset? // TODO: may not work correctly with reloc data? diff --git a/SourceGen/WpfGui/CodeListItemStyle.xaml b/SourceGen/WpfGui/CodeListItemStyle.xaml index aa6e30d..9b32fd2 100644 --- a/SourceGen/WpfGui/CodeListItemStyle.xaml +++ b/SourceGen/WpfGui/CodeListItemStyle.xaml @@ -407,4 +407,22 @@ See also https://github.com/fadden/DisasmUiTest + + + + + + + + + + \ No newline at end of file diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml index 94bd636..55ec836 100644 --- a/SourceGen/WpfGui/MainWindow.xaml +++ b/SourceGen/WpfGui/MainWindow.xaml @@ -771,7 +771,7 @@ limitations under the License. + CellTemplate="{StaticResource operandHighlightTemplate}"/> diff --git a/SourceGen/WpfGui/MainWindow.xaml.cs b/SourceGen/WpfGui/MainWindow.xaml.cs index fba729c..bd60035 100644 --- a/SourceGen/WpfGui/MainWindow.xaml.cs +++ b/SourceGen/WpfGui/MainWindow.xaml.cs @@ -981,24 +981,48 @@ namespace SourceGen.WpfGui { /// Adds an address/label selection highlight to the specified line. /// /// Line index. If < 0, method has no effect. - public void CodeListView_AddSelectionHighlight(int index) { + public void CodeListView_AddSelectionAddrHighlight(int index) { if (index < 0) { return; } CodeListView_ReplaceEntry(index, - DisplayList.FormattedParts.AddSelectionHighlight(CodeDisplayList[index])); + DisplayList.FormattedParts.AddSelectionAddrHighlight(CodeDisplayList[index])); } /// /// Removes an address/label selection highlight from the specified line. /// /// Line index. If < 0, method has no effect. - public void CodeListView_RemoveSelectionHighlight(int index) { + public void CodeListView_RemoveSelectionAddrHighlight(int index) { if (index < 0) { return; } CodeListView_ReplaceEntry(index, - DisplayList.FormattedParts.RemoveSelectionHighlight(CodeDisplayList[index])); + DisplayList.FormattedParts.RemoveSelectionAddrHighlight(CodeDisplayList[index])); + } + + /// + /// Adds an operand selection highlight to the specified line. + /// + public void CodeListView_AddSelectionOperHighlight(int index) { + Debug.Assert(index >= 0); + CodeListView_ReplaceEntry(index, + DisplayList.FormattedParts.AddSelectionOperHighlight(CodeDisplayList[index])); + } + + /// + /// Removes an operand selection highlight from the specified line. + /// + public void CodeListView_RemoveSelectionOperHighlight(int index) { + Debug.Assert(index >= 0); + if (index >= CodeDisplayList.Count) { + // Shouldn't happen unless we resize the list without clearing the highlights. + Debug.WriteLine("NOTE: selection oper high index exceeds count (" + + index + " vs. " + CodeDisplayList.Count + ")"); + return; + } + CodeListView_ReplaceEntry(index, + DisplayList.FormattedParts.RemoveSelectionOperHighlight(CodeDisplayList[index])); } ///