diff --git a/PluginCommon/Interfaces.cs b/PluginCommon/Interfaces.cs index ff2b347..05dde90 100644 --- a/PluginCommon/Interfaces.cs +++ b/PluginCommon/Interfaces.cs @@ -29,7 +29,7 @@ namespace PluginCommon { string Identifier { get; } /// - /// Prepares the plugin for action. Called at the start of the code analysis pass. + /// Prepares the plugin for action. Called at the start of every code analysis pass. /// /// In the current implementation, the file data will be the same every time, /// because it doesn't change after the project is opened. However, this could @@ -38,11 +38,44 @@ namespace PluginCommon { /// Reference to application interface. /// 65xx code and data. /// Mapping between offsets and addresses. - /// Symbols available to plugins, in no particular order. All - /// platform, project, and user labels are included; auto-generated symbols and - /// local variables are not. - void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms); + void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans); + } + + /// + /// Extension scripts that want to receive the list of symbols must implement this interface. + /// + public interface IPlugin_SymbolList { + /// + /// Receives a list of the currently defined platform, project, and user symbols. + /// The list does not include auto-generated labels or local variables. + /// + /// This is called immediately after Prepare(), before any other interfaces are + /// invoked, at the start of every code analysis pass. + /// + /// Symbols available to plugins, in no particular order. + void UpdateSymbolList(List plSyms); + + /// + /// Handles a notification that a user symbol has been added, edited, or removed. If the + /// label is of interest to the plugin, e.g. it changes how the plugin formats code or + /// data, the app needs to know. + /// + /// + /// The application does a full re-analysis when project properties change, but not + /// when labels are edited. The CheckJsr/Jsl/Brk methods are only called during code + /// analysis, so if their behavior changes based on the presence or absence of a user + /// label then we need to tell the application that a full re-analysis is needed. + /// + /// Plugins that don't care about user symbols, e.g. that just use tagged platform + /// symbols, can simply return false. (Changes to user labels that overlap with + /// project/platform symbols are detected by the app.) + /// + /// The label before the change, or empty if this is a + /// newly-added label. + /// The label after the change, or empty if the label was + /// removed. + /// True if the label change could affect the plugin's actions. + bool IsLabelSignificant(string beforeLabel, string afterLabel); } /// @@ -128,6 +161,9 @@ namespace PluginCommon { /// /// Data format type. /// + /// + /// Essentially a clone of FormatDescriptor.Type. + /// public enum DataType { Unknown = 0, NumericLE, @@ -145,6 +181,9 @@ namespace PluginCommon { /// /// Data format sub-type. /// + /// + /// Essentially a clone of FormatDescriptor.SubType. + /// public enum DataSubType { // No sub-type specified. None = 0, diff --git a/PluginCommon/PluginManager.cs b/PluginCommon/PluginManager.cs index bbee8df..dba75db 100644 --- a/PluginCommon/PluginManager.cs +++ b/PluginCommon/PluginManager.cs @@ -154,15 +154,37 @@ namespace PluginCommon { /// Invokes the Prepare() method on all active plugins. /// /// Reference to host object providing app services. + /// Serialized AddressMap entries. + /// SymbolTable contents, converted to PlSymbol. public void PreparePlugins(IApplication appRef, List addrEntries, List plSyms) { AddressMap addrMap = new AddressMap(addrEntries); AddressTranslate addrTrans = new AddressTranslate(addrMap); foreach (KeyValuePair kvp in mActivePlugins) { - kvp.Value.Prepare(appRef, mFileData, addrTrans, plSyms); + IPlugin ipl = kvp.Value; + ipl.Prepare(appRef, mFileData, addrTrans); + if (ipl is IPlugin_SymbolList) { + ((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms); + } } } + /// + /// Returns true if any of the plugins report that the before or after label is + /// significant. + /// + public bool IsLabelSignificant(string labelBefore, string labelAfter) { + foreach (KeyValuePair kvp in mActivePlugins) { + IPlugin ipl = kvp.Value; + if (ipl is IPlugin_SymbolList && + ((IPlugin_SymbolList)ipl).IsLabelSignificant(labelBefore, + labelAfter)) { + return true; + } + } + return false; + } + #if false /// /// DEBUG ONLY: establish a fast lease timeout. Normally the lease diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index 7b5b639..eda1c95 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -1970,6 +1970,16 @@ namespace SourceGen { // to do the refactor here, though we can skip Anattribs work. Debug.Assert(oldValue == null || newValue == null); } + + // For add/edit/remove, we need to see if what we do will impact + // the behavior of a plugin. We don't need to do this on + // project/platform symbol changes because project property changes + // always update code and data. + if (mScriptManager.IsLabelSignificant((Symbol)oldValue, + (Symbol)newValue)) { + Debug.WriteLine("Plugin claims symbol is significant"); + needReanalysis |= UndoableChange.ReanalysisScope.CodeAndData; + } } break; case UndoableChange.ChangeType.SetOperandFormat: { diff --git a/SourceGen/Examples/Scripts/InlineL1String.cs b/SourceGen/Examples/Scripts/InlineL1String.cs new file mode 100644 index 0000000..5ff0212 --- /dev/null +++ b/SourceGen/Examples/Scripts/InlineL1String.cs @@ -0,0 +1,74 @@ +// Copyright 2019 faddenSoft. All Rights Reserved. +// See the LICENSE.txt file for distribution terms (Apache 2.0). + +using System; +using System.Collections.Generic; + +using PluginCommon; + +namespace ExtensionScriptSample { + /// + /// Sample class for handling a JSR followed by a string prefixed with a 1-byte length. + /// + public class InlineL1String: MarshalByRefObject, IPlugin, IPlugin_SymbolList, + IPlugin_InlineJsr { + private IApplication mAppRef; + private byte[] mFileData; + + // Only one call. + private const string CALL_LABEL = "PrintInlineL1String"; + private int mInlineL1StringAddr; // jsr + + public string Identifier { + get { + return "Inline L1 ASCII string handler"; + } + } + + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { + mAppRef = appRef; + mFileData = fileData; + + mAppRef.DebugLog("InlineL1String(id=" + + AppDomain.CurrentDomain.Id + "): prepare()"); + } + + public void UpdateSymbolList(List plSyms) { + // reset this every time, in case they remove the symbol + mInlineL1StringAddr = -1; + + foreach (PlSymbol sym in plSyms) { + if (sym.Label == CALL_LABEL) { + mInlineL1StringAddr = sym.Value; + break; + } + } + mAppRef.DebugLog(CALL_LABEL + " @ $" + mInlineL1StringAddr.ToString("x6")); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return beforeLabel == CALL_LABEL || afterLabel == CALL_LABEL; + } + + public void CheckJsr(int offset, out bool noContinue) { + noContinue = false; + int target = Util.GetWord(mFileData, offset + 1, 2, false); + if (target != mInlineL1StringAddr) { + return; + } + if (offset + 3 >= mFileData.Length) { + return; // length byte is off end + } + int len = mFileData[3]; // first byte past JSR + if (offset + 4 + len > mFileData.Length) { + mAppRef.DebugLog("L1 string ran off end of file at +" + + (offset + 4).ToString("x6")); + return; + } + + // Assuming ASCII. This can be hard-coded, use auto-detection, or look + // up a value in a project constant. + mAppRef.SetInlineDataFormat(offset + 3, len + 1, + DataType.StringL8, DataSubType.Ascii, null); + } + } +} diff --git a/SourceGen/Examples/Scripts/InlineNullTerm.cs b/SourceGen/Examples/Scripts/InlineNullTerm.cs deleted file mode 100644 index 30431ba..0000000 --- a/SourceGen/Examples/Scripts/InlineNullTerm.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 faddenSoft. All Rights Reserved. -// See the LICENSE.txt file for distribution terms (Apache 2.0). - -using System; -using System.Collections.Generic; - -using PluginCommon; - -namespace ExtensionScriptSample { - /// - /// Sample class for handling a JSR followed by an inline null-terminated string. - /// - public class InlineNullStringHandler : MarshalByRefObject, IPlugin, IPlugin_InlineJsr { - private IApplication mAppRef; - private byte[] mFileData; - - private int mInlineNullStringAddr; // jsr - - public string Identifier { - get { - return "Inline null-terminated ASCII string handler"; - } - } - - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { - mAppRef = appRef; - mFileData = fileData; - - mAppRef.DebugLog("InlineNullStringHandler(id=" + - AppDomain.CurrentDomain.Id + "): prepare()"); - - // reset this every time, in case they remove the label - mInlineNullStringAddr = -1; - foreach (PlSymbol sym in plSyms) { - if (sym.Label == "PrintInlineZString") { - mInlineNullStringAddr = sym.Value; - break; - } - } - mAppRef.DebugLog("PrintInlineZString @ $" + mInlineNullStringAddr.ToString("x6")); - } - - public void CheckJsr(int offset, out bool noContinue) { - noContinue = false; - int target = Util.GetWord(mFileData, offset + 1, 2, false); - if (target == mInlineNullStringAddr) { - // search for the terminating null byte - int nullOff = offset + 3; - while (nullOff < mFileData.Length) { - if (mFileData[nullOff] == 0) { - break; - } - nullOff++; - } - if (nullOff == mFileData.Length) { - mAppRef.DebugLog("Unable to find end of null-terminated string at +" + - (offset+3).ToString("x6")); - return; - } - - // Assuming ASCII. This can be hard-coded, use auto-detection, or look - // up a value in a project constant. - mAppRef.SetInlineDataFormat(offset + 3, nullOff - (offset + 3) + 1, - DataType.StringNullTerm, DataSubType.Ascii, null); - } - } - } -} diff --git a/SourceGen/Examples/Scripts/InlineNullTermString.cs b/SourceGen/Examples/Scripts/InlineNullTermString.cs new file mode 100644 index 0000000..e5453ee --- /dev/null +++ b/SourceGen/Examples/Scripts/InlineNullTermString.cs @@ -0,0 +1,77 @@ +// Copyright 2019 faddenSoft. All Rights Reserved. +// See the LICENSE.txt file for distribution terms (Apache 2.0). + +using System; +using System.Collections.Generic; + +using PluginCommon; + +namespace ExtensionScriptSample { + /// + /// Sample class for handling a JSR followed by an inline null-terminated string. Any + /// label that starts with "PrintLineNullString" is matched. + /// + public class InlineNullTermString : MarshalByRefObject, IPlugin, IPlugin_SymbolList, + IPlugin_InlineJsr { + private IApplication mAppRef; + private byte[] mFileData; + + private const string LABEL_PREFIX = "PrintInlineNullString"; + private Dictionary mNullStringAddrs = new Dictionary(); + + public string Identifier { + get { + return "Inline null-terminated ASCII string handler"; + } + } + + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { + mAppRef = appRef; + mFileData = fileData; + + mAppRef.DebugLog("InlineNullStringHandler(id=" + + AppDomain.CurrentDomain.Id + "): prepare()"); + } + + public void UpdateSymbolList(List plSyms) { + mNullStringAddrs.Clear(); + + foreach (PlSymbol sym in plSyms) { + if (sym.Label.StartsWith(LABEL_PREFIX)) { + mNullStringAddrs.Add(sym.Value, sym); + } + } + mAppRef.DebugLog(LABEL_PREFIX + " matched " + mNullStringAddrs.Count + " labels"); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return beforeLabel.StartsWith(LABEL_PREFIX) || afterLabel.StartsWith(LABEL_PREFIX); + } + + public void CheckJsr(int offset, out bool noContinue) { + noContinue = false; + int target = Util.GetWord(mFileData, offset + 1, 2, false); + if (!mNullStringAddrs.ContainsKey(target)) { + return; + } + + // search for the terminating null byte + int nullOff = offset + 3; + while (nullOff < mFileData.Length) { + if (mFileData[nullOff] == 0) { + break; + } + nullOff++; + } + if (nullOff == mFileData.Length) { + mAppRef.DebugLog("Unable to find end of null-terminated string at +" + + (offset+3).ToString("x6")); + return; + } + + // Assuming ASCII. This can be hard-coded, use auto-detection, or look + // up a value in a project constant. + mAppRef.SetInlineDataFormat(offset + 3, nullOff - (offset + 3) + 1, + DataType.StringNullTerm, DataSubType.Ascii, null); + } + } +} diff --git a/SourceGen/Examples/Scripts/Sample b/SourceGen/Examples/Scripts/Sample index 4f43070..c8968a9 100644 Binary files a/SourceGen/Examples/Scripts/Sample and b/SourceGen/Examples/Scripts/Sample differ diff --git a/SourceGen/Examples/Scripts/Sample.S b/SourceGen/Examples/Scripts/Sample.S index 9ddddb2..8c2f85a 100644 --- a/SourceGen/Examples/Scripts/Sample.S +++ b/SourceGen/Examples/Scripts/Sample.S @@ -1,8 +1,18 @@ org $1000 - jsr PrintInlineZString - asc 'Testing',00 + jsr PrintInlineL1String + str 'How long?' + + jsr PrintInlineZString1 + asc 'Test one',00 + + jsr PrintInlineZString2 + asc 'Test two',00 rts -PrintInlineZString +PrintInlineL1String + rts +PrintInlineZString1 + rts +PrintInlineZString2 rts diff --git a/SourceGen/Examples/Scripts/Sample.dis65 b/SourceGen/Examples/Scripts/Sample.dis65 index e63fc3e..0f7e6d2 100644 --- a/SourceGen/Examples/Scripts/Sample.dis65 +++ b/SourceGen/Examples/Scripts/Sample.dis65 @@ -1,9 +1,9 @@ ### 6502bench SourceGen dis65 v1.0 ### { -"_ContentVersion":2,"FileDataLength":13,"FileDataCrc32":205674068,"ProjectProps":{ -"CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{ +"_ContentVersion":2,"FileDataLength":41,"FileDataCrc32":-1863359703,"ProjectProps":{ +"CpuName":"6502","IncludeUndocumentedInstr":false,"TwoByteBrk":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{ "AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true}, -"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":["PROJ:InlineNullTerm.cs"],"ProjectSyms":{ +"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":["PROJ:InlineL1String.cs","PROJ:InlineNullTermString.cs"],"ProjectSyms":{ }}, "AddressMap":[{ "Offset":0,"Addr":4096}],"TypeHints":[{ @@ -16,8 +16,12 @@ "Notes":{ }, "UserLabels":{ -"12":{ -"Label":"PrintInlineZString","Value":4108,"Source":"User","Type":"LocalOrGlobalAddr"}}, +"38":{ +"Label":"PrintInlineL1String","Value":4134,"Source":"User","Type":"LocalOrGlobalAddr"}, +"39":{ +"Label":"PrintInlineNullString1","Value":4135,"Source":"User","Type":"LocalOrGlobalAddr"}, +"40":{ +"Label":"PrintInlineNullString2","Value":4136,"Source":"User","Type":"LocalOrGlobalAddr"}}, "OperandFormats":{ }, "LvTables":{ diff --git a/SourceGen/RuntimeData/Apple/GSOS.cs b/SourceGen/RuntimeData/Apple/GSOS.cs index 57ffa15..ce3a96d 100644 --- a/SourceGen/RuntimeData/Apple/GSOS.cs +++ b/SourceGen/RuntimeData/Apple/GSOS.cs @@ -34,7 +34,7 @@ using PluginCommon; */ namespace RuntimeData.Apple { - public class GSOS : MarshalByRefObject, IPlugin, IPlugin_InlineJsl { + public class GSOS : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsl { private const string GSOS_FUNC_TAG = "AppleIIgs-GSOS-Functions"; // tag used in .sym65 file private bool VERBOSE = false; @@ -48,15 +48,21 @@ namespace RuntimeData.Apple { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAppRef.DebugLog("GSOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); //System.Diagnostics.Debugger.Break(); - mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, GSOS_FUNC_TAG, appRef); + } + + public void UpdateSymbolList(List plSyms) { + // Extract the list of function name constants from the platform symbol file. + mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, GSOS_FUNC_TAG, mAppRef); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return false; } public void CheckJsl(int offset, out bool noContinue) { diff --git a/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs b/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs index 4556ca9..744b04c 100644 --- a/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs +++ b/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs @@ -27,8 +27,8 @@ using PluginCommon; */ namespace RuntimeData.Apple { - public class IIgsToolbox : MarshalByRefObject, IPlugin, IPlugin_InlineJsl { - private const string TOOLBOX_FUNC_TAG = "AppleIIgs-Toolbox-Functions"; // tag used in .sym65 file + public class IIgsToolbox : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsl { + private const string TOOLBOX_FUNC_TAG = "AppleIIgs-Toolbox-Functions"; // tag used in .sym65 file private bool VERBOSE = false; private IApplication mAppRef; @@ -41,14 +41,19 @@ namespace RuntimeData.Apple { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAppRef.DebugLog("IIgsToolbox(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); + } - mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, TOOLBOX_FUNC_TAG, appRef); + public void UpdateSymbolList(List plSyms) { + // Extract the list of function name constants from the platform symbol file. + mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, TOOLBOX_FUNC_TAG, mAppRef); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return false; } public void CheckJsl(int offset, out bool noContinue) { diff --git a/SourceGen/RuntimeData/Apple/ProDOS8.cs b/SourceGen/RuntimeData/Apple/ProDOS8.cs index 806f0e0..696dac5 100644 --- a/SourceGen/RuntimeData/Apple/ProDOS8.cs +++ b/SourceGen/RuntimeData/Apple/ProDOS8.cs @@ -29,7 +29,7 @@ parm_block */ namespace RuntimeData.Apple { - public class ProDOS8 : MarshalByRefObject, IPlugin, IPlugin_InlineJsr { + public class ProDOS8 : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsr { private const string P8_MLI_TAG = "ProDOS8-MLI-Functions"; // tag used in .sym65 file private bool VERBOSE = false; @@ -161,8 +161,7 @@ namespace RuntimeData.Apple { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAddrTrans = addrTrans; @@ -170,8 +169,13 @@ namespace RuntimeData.Apple { mAppRef.DebugLog("ProDOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); //System.Diagnostics.Debugger.Break(); + } + public void UpdateSymbolList(List plSyms) { // Extract the list of function name constants from the platform symbol file. - mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, appRef); + mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, mAppRef); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return false; } public void CheckJsr(int offset, out bool noContinue) { diff --git a/SourceGen/RuntimeData/Apple/SOS.cs b/SourceGen/RuntimeData/Apple/SOS.cs index 187892a..93eb325 100644 --- a/SourceGen/RuntimeData/Apple/SOS.cs +++ b/SourceGen/RuntimeData/Apple/SOS.cs @@ -29,7 +29,7 @@ parm_block */ namespace RuntimeData.Apple { - public class SOS : MarshalByRefObject, IPlugin, IPlugin_InlineBrk { + public class SOS : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineBrk { private const string SOS_MLI_TAG = "SOS-MLI-Functions"; // tag used in .sym65 file private bool VERBOSE = true; @@ -43,15 +43,20 @@ namespace RuntimeData.Apple { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAppRef.DebugLog("SOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); //System.Diagnostics.Debugger.Break(); + } - mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, SOS_MLI_TAG, appRef); + public void UpdateSymbolList(List plSyms) { + // Extract the list of function name constants from the platform symbol file. + mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, SOS_MLI_TAG, mAppRef); + } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + return false; } public void CheckBrk(int offset, bool twoByteBrk, out bool noContinue) { diff --git a/SourceGen/RuntimeData/Help/advanced.html b/SourceGen/RuntimeData/Help/advanced.html index 6315e47..e1f9c3a 100644 --- a/SourceGen/RuntimeData/Help/advanced.html +++ b/SourceGen/RuntimeData/Help/advanced.html @@ -115,13 +115,6 @@ invoked is not defined.

Known Issues and Limitations

-

Sometimes a manual refresh (F5) is required. Plugins are executed during -the code analysis pass, but SourceGen doesn't perform code analysis on -every change. If you add or change a label that a plugin is looking -for, you won't see the effects until you do something that causes the -code analysis pass to be run. Hitting F5 does this. (There's no easy -way around this -- either we have to re-run code analysis on every label -change, or we need a way to know which labels a plugin is interested in.)

When a project is opened, any errors encountered by the script compiler are reported to the user. If the project is already open, and a script is added to the project through the Project Properties editor, compiler diff --git a/SourceGen/SGTestData/2011-hinting.cs b/SourceGen/SGTestData/2011-hinting.cs index 34837c8..8889c05 100644 --- a/SourceGen/SGTestData/2011-hinting.cs +++ b/SourceGen/SGTestData/2011-hinting.cs @@ -17,8 +17,7 @@ namespace RuntimeData.Test2011 { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; diff --git a/SourceGen/SGTestData/2022-extension-scripts-a.cs b/SourceGen/SGTestData/2022-extension-scripts-a.cs index 9ab8639..fbeefc5 100644 --- a/SourceGen/SGTestData/2022-extension-scripts-a.cs +++ b/SourceGen/SGTestData/2022-extension-scripts-a.cs @@ -7,7 +7,8 @@ using System.Collections.Generic; using PluginCommon; namespace RuntimeData.Test2022 { - public class Test2022A : MarshalByRefObject, IPlugin, IPlugin_InlineJsr, IPlugin_InlineJsl { + public class Test2022A : MarshalByRefObject, IPlugin, IPlugin_SymbolList, + IPlugin_InlineJsr, IPlugin_InlineJsl { private IApplication mAppRef; private byte[] mFileData; @@ -24,13 +25,13 @@ namespace RuntimeData.Test2022 { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAppRef.DebugLog("Test2022-A(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); - + } + public void UpdateSymbolList(List plSyms) { foreach (PlSymbol sym in plSyms) { switch (sym.Label) { case "PrintInline8String": @@ -55,6 +56,11 @@ namespace RuntimeData.Test2022 { } } + public bool IsLabelSignificant(string beforeLabel, string afterLabel) { + const string PREFIX = "PrintInline"; // all interesting labels start with this + return (beforeLabel.StartsWith(PREFIX) || afterLabel.StartsWith(PREFIX)); + } + public void CheckJsr(int offset, out bool noContinue) { noContinue = false; int target = Util.GetWord(mFileData, offset + 1, 2, false); @@ -99,6 +105,9 @@ namespace RuntimeData.Test2022 { if (target == mInlineL1StringAddr) { // 0 1 2 3 4 5 // 22 00 10 01 01 66 + if (offset + 4 >= mFileData.Length) { + return; // length byte is off end + } int len = mFileData[offset + 4]; // 1-byte len in first byte past 4-byte JSL if (offset + 5 + len > mFileData.Length) { // ran off the end @@ -109,6 +118,9 @@ namespace RuntimeData.Test2022 { mAppRef.SetInlineDataFormat(offset + 4, len + 1, DataType.StringL8, DataSubType.Ascii, null); } else if (target == mInlineL2StringAddr) { + if (offset + 5 >= mFileData.Length) { + return; // length word is off end + } int len = Util.GetWord(mFileData, offset + 4, 2, false); if (offset + 6 + len > mFileData.Length) { // ran off the end @@ -118,7 +130,7 @@ namespace RuntimeData.Test2022 { } mAppRef.SetInlineDataFormat(offset + 4, len + 2, DataType.StringL16, DataSubType.Ascii, null); - } else { + } else if (target == mInlineDciStringAddr) { // look for the first byte whose high bit doesn't match the first byte's bit // 0 1 2 3 4 5 // 22 00 30 01 66 c1 diff --git a/SourceGen/SGTestData/2022-extension-scripts-b.cs b/SourceGen/SGTestData/2022-extension-scripts-b.cs index 1bef8d8..deabeab 100644 --- a/SourceGen/SGTestData/2022-extension-scripts-b.cs +++ b/SourceGen/SGTestData/2022-extension-scripts-b.cs @@ -18,8 +18,7 @@ namespace RuntimeData.Test2022 { } } - public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans, - List plSyms) { + public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; mAddrTrans = addrTrans; diff --git a/SourceGen/Sandbox/ScriptManager.cs b/SourceGen/Sandbox/ScriptManager.cs index a3819a4..cc4b848 100644 --- a/SourceGen/Sandbox/ScriptManager.cs +++ b/SourceGen/Sandbox/ScriptManager.cs @@ -161,7 +161,11 @@ namespace SourceGen.Sandbox { if (DomainMgr == null) { AddressTranslate addrTrans = new AddressTranslate(mProject.AddrMap); foreach (KeyValuePair kvp in mActivePlugins) { - kvp.Value.Prepare(appRef, mProject.FileData, addrTrans, plSyms); + IPlugin ipl = kvp.Value; + ipl.Prepare(appRef, mProject.FileData, addrTrans); + if (ipl is IPlugin_SymbolList) { + ((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms); + } } } else { List addrEnts = mProject.AddrMap.GetEntryList(); @@ -169,6 +173,28 @@ namespace SourceGen.Sandbox { } } + ///

+ /// Returns true if any of the plugins report that the before or after label is + /// significant. + /// + public bool IsLabelSignificant(Symbol before, Symbol after) { + string labelBefore = (before == null) ? string.Empty : before.Label; + string labelAfter = (after == null) ? string.Empty : after.Label; + if (DomainMgr == null) { + foreach (KeyValuePair kvp in mActivePlugins) { + IPlugin ipl = kvp.Value; + if (ipl is IPlugin_SymbolList && + ((IPlugin_SymbolList)ipl).IsLabelSignificant(labelBefore, + labelAfter)) { + return true; + } + } + return false; + } else { + return DomainMgr.PluginMgr.IsLabelSignificant(labelBefore, labelAfter); + } + } + /// /// Gathers a list of platform symbols from the project's symbol table. /// @@ -261,6 +287,9 @@ namespace SourceGen.Sandbox { // The plugin is actually a MarshalByRefObject, so we can't use reflection // to gather the list of interfaces. // TODO(maybe): add a call that does the query on the remote site + if (plugin is PluginCommon.IPlugin_SymbolList) { + sb.Append(" SymbolList"); + } if (plugin is PluginCommon.IPlugin_InlineJsr) { sb.Append(" InlineJsr"); }