1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-12 08:29:29 +00:00

Rename "hints" to "analyzer tags"

Variables, types, and comments have been updated to reflect the new
naming scheme.

The project file serialization code is untouched, because the data
is output as serialized enumerated values.  Adding a string conversion
layer didn't seem worthwhile.

No changes in behavior.

(issue #89)
This commit is contained in:
Andy McFadden 2020-10-15 14:03:32 -07:00
parent 908a1c9900
commit 49f4017410
15 changed files with 196 additions and 196 deletions

View File

@ -48,7 +48,7 @@ namespace SourceGen {
Visited = 1 << 16, // has the analyzer visited this byte?
Changed = 1 << 17, // set/cleared as the analyzer works
Hinted = 1 << 18, // was this byte affected by a type hint?
ATagged = 1 << 18, // was this byte affected by an analyzer tag?
}
// Flags indicating what type of data is here. Use the following Is* properties
@ -219,15 +219,15 @@ namespace SourceGen {
}
}
}
public bool IsHinted {
public bool HasAnalyzerTag {
get {
return (mAttribFlags & AttribFlags.Hinted) != 0;
return (mAttribFlags & AttribFlags.ATagged) != 0;
}
set {
if (value) {
mAttribFlags |= AttribFlags.Hinted;
mAttribFlags |= AttribFlags.ATagged;
} else {
mAttribFlags &= ~AttribFlags.Hinted;
mAttribFlags &= ~AttribFlags.ATagged;
}
}
}
@ -381,7 +381,7 @@ namespace SourceGen {
StringBuilder sb = new StringBuilder(5);
char blank = '.';
sb.Append(IsEntryPoint ? '@' : blank);
sb.Append(IsHinted ? 'T' : blank);
sb.Append(HasAnalyzerTag ? 'T' : blank);
sb.Append(DoesNotBranch ? '!' : blank);
sb.Append(DoesNotContinue ? '#' : blank);
sb.Append(IsBranchTarget ? '>' : blank);

View File

@ -34,35 +34,38 @@ namespace SourceGen {
/// See the comments at the top of UndoableChange for a list of things that can
/// mandate code re-analysis.
/// </summary>
/// <remarks>
/// This invokes methods in extension scripts to handle things like inline data
/// following a JSR. The added cost is generally low, because the AppDomain security
/// sandbox doesn't add a lot of overhead. Unfortunately this approach is deprecated
/// by Microsoft and may break or become unavailable. If that happens, and we have to
/// switch to a sandbox approach with significant overhead, we will most likely want
/// to move the code analyzer itself into the sandbox.
///
/// For this reason it's best to minimize direct interaction between the code here and
/// that elsewhere in the program.
/// </remarks>
public class CodeAnalysis {
/// <summary>
/// Type hints are specified by the user. The identify a region as being code
/// or data. The code analyzer will stop at data-hinted regions, and will
/// process any code-hinted regions during the dead-code pass.
///
/// The hints are not used directly by the data analyzer, but the effects they
/// Analyzer tags are specified by the user. They identify an offset as being the
/// start or end of an executable code region, or part of an inline data block.
///
/// The tags are not used directly by the data analyzer, but the effects they
/// have on the Anattrib array are.
/// </summary>
/// <remarks>
/// This invokes methods in extension scripts to handle things like inline data
/// following a JSR. The added cost is generally low, because the AppDomain security
/// sandbox doesn't add a lot of overhead. Unfortunately this approach is deprecated
/// by Microsoft and may break or become unavailable. If that happens, and we have to
/// switch to a sandbox approach with significant overhead, we will most likely want
/// to move the code analyzer itself into the sandbox.
///
/// For this reason it's best to minimize direct interaction between the code here and
/// that elsewhere in the program.
/// THESE VALUES ARE SERIALIZED to the project data file. They cannot be renamed
/// without writing a translator in ProjectFile.
/// </remarks>
public enum TypeHint : sbyte {
// No hint. Default value populated in new arrays.
NoHint = 0,
public enum AnalyzerTag : sbyte {
// No tag. Default value populated in new arrays.
None = 0,
// Byte is an instruction. If the code analyzer doesn't find this
// naturally, it will be scanned.
Code,
// Byte is inline data. Execution continues "through" the byte.
// Byte is inline data. Execution skips over the byte.
InlineData,
// Byte is data. Execution halts.
@ -147,9 +150,9 @@ namespace SourceGen {
private Anattrib[] mAnattribs;
/// <summary>
/// Reference to type hint array, one hint per byte.
/// Reference to analyzer tag array, one entry per byte.
/// </summary>
private TypeHint[] mTypeHints;
private AnalyzerTag[] mAnalyzerTags;
/// <summary>
/// Reference to status flag override array, one entry per byte.
@ -180,7 +183,7 @@ namespace SourceGen {
/// <param name="anattribs">Anattrib array. Expected to be newly allocated, all
/// entries set to default values.</param>
/// <param name="addrMap">Map of offsets to addresses.</param>
/// <param name="hints">Type hints, one per byte.</param>
/// <param name="atags">Analyzer tags, one per byte.</param>
/// <param name="statusFlagOverrides">Status flag overrides for instruction-start
/// bytes.</param>
/// <param name="entryFlags">Status flags to use at code entry points.</param>
@ -188,14 +191,14 @@ namespace SourceGen {
/// <param name="parms">Analysis parameters.</param>
/// <param name="debugLog">Object that receives debug log messages.</param>
public CodeAnalysis(byte[] data, CpuDef cpuDef, Anattrib[] anattribs,
AddressMap addrMap, TypeHint[] hints, StatusFlags[] statusFlagOverrides,
AddressMap addrMap, AnalyzerTag[] atags, StatusFlags[] statusFlagOverrides,
StatusFlags entryFlags, ProjectProperties.AnalysisParameters parms,
ScriptManager scriptMan, DebugLog debugLog) {
mFileData = data;
mCpuDef = cpuDef;
mAnattribs = anattribs;
mAddrMap = addrMap;
mTypeHints = hints;
mAnalyzerTags = atags;
mStatusFlagOverrides = statusFlagOverrides;
mEntryFlags = entryFlags;
mScriptManager = scriptMan;
@ -263,19 +266,19 @@ namespace SourceGen {
SetAddresses();
// Set the "is data" and "is inline data" flags on anything that the user has
// flagged as being such. This tells us to stop processing or skip over bytes
// as we work. We don't need to flag code hints explicitly for analysis, but
// we want to be able to display the flags in the info window.
// Set values in the anattrib array based on the user-specified analyzer tags.
// This tells us to stop processing or skip over bytes as we work. We set values
// for the code start tags so we can show them in the "info" window.
//
// The data recognizers may spot additional inline data offsets as we work. This
// can cause a race if it mis-identifies code that is also a branch target;
// whichever marks the code first will win.
UnpackTypeHints();
UnpackAnalyzerTags();
// Find starting place, based on type hints.
// Find starting place, based on analyzer tags.
//
// We only set the "visited" flag on the instruction start, so if the user
// puts a code hint in the middle of an instruction, we will find it and
// puts a code start in the middle of an instruction, we will find it and
// treat it as an entry point. (This is useful for embedded instructions
// that are branched to by code we aren't able to detect.)
int searchStart = FindFirstUnvisitedInstruction(0);
@ -363,37 +366,36 @@ namespace SourceGen {
}
/// <summary>
/// Sets the "is xxxxx" flags on type-hinted entries, so that the code analyzer
/// Sets the "is xxxxx" flags on analyzer-tagged entries, so that the code analyzer
/// can find them easily.
/// </summary>
private void UnpackTypeHints() {
Debug.Assert(mTypeHints.Length == mAnattribs.Length);
private void UnpackAnalyzerTags() {
Debug.Assert(mAnalyzerTags.Length == mAnattribs.Length);
int offset = 0;
foreach (TypeHint hint in mTypeHints) {
switch (hint) {
case TypeHint.Code:
foreach (AnalyzerTag atag in mAnalyzerTags) {
switch (atag) {
case AnalyzerTag.Code:
// Set the IsInstruction flag to prevent inline data from being
// placed here.
OpDef op = mCpuDef.GetOpDef(mFileData[offset]);
if (op == OpDef.OpInvalid) {
LogI(offset, "Ignoring code hint on illegal opcode");
LogI(offset, "Ignoring code start tag on illegal opcode");
} else {
mAnattribs[offset].IsHinted = true;
mAnattribs[offset].HasAnalyzerTag = true;
mAnattribs[offset].IsInstruction = true;
}
break;
case TypeHint.Data:
// Tells the code analyzer to stop. Does not define a data analyzer
// "uncategorized data" boundary.
mAnattribs[offset].IsHinted = true;
case AnalyzerTag.Data:
// Tells the code analyzer to stop.
mAnattribs[offset].HasAnalyzerTag = true;
mAnattribs[offset].IsData = true;
break;
case TypeHint.InlineData:
case AnalyzerTag.InlineData:
// Tells the code analyzer to walk across these.
mAnattribs[offset].IsHinted = true;
mAnattribs[offset].HasAnalyzerTag = true;
mAnattribs[offset].IsInlineData = true;
break;
case TypeHint.NoHint:
case AnalyzerTag.None:
break;
default:
Debug.Assert(false);
@ -404,21 +406,21 @@ namespace SourceGen {
}
/// <summary>
/// Finds the first offset that is hinted as code but hasn't yet been visited.
///
/// Finds the first offset that is tagged as code start but hasn't yet been visited.
///
/// This might be in the middle of an already-visited instruction.
/// </summary>
/// <param name="start">Offset at which to start the search.</param>
/// <returns>Offset found.</returns>
private int FindFirstUnvisitedInstruction(int start) {
for (int i = start; i < mAnattribs.Length; i++) {
if (mAnattribs[i].IsHinted && mTypeHints[i] == TypeHint.Code &&
if (mAnattribs[i].HasAnalyzerTag && mAnalyzerTags[i] == AnalyzerTag.Code &&
!mAnattribs[i].IsVisited) {
LogD(i, "Unvisited code hint");
LogD(i, "Unvisited code start tag");
if (mAnattribs[i].IsData || mAnattribs[i].IsInlineData) {
// Maybe the user put a code hint on something that was
// Maybe the user put a code start tag on something that was
// later recognized as inline data? Shouldn't have been allowed.
LogW(i, "Weird: code hint on data/inline");
LogW(i, "Weird: code start tag on data/inline");
continue;
}
return i;
@ -498,7 +500,7 @@ namespace SourceGen {
} else if (mAnattribs[offset].IsInlineData) {
// Generally this won't happen, because we ignore branches into inline data
// areas, we reject attempts to convert code to inline data, and we can't
// start in an inline area because the hint is wrong. However, it's possible
// start in an inline area because the tag is wrong. However, it's possible
// for a JSR to a new section to be registered, and then before we get to
// it an extension script formats the area as inline data. In that case
// the inline data "wins", and we stop here.
@ -545,8 +547,8 @@ namespace SourceGen {
// instruction, but bytes within the instruction are marked as data. The
// easiest thing to do here is steamroll the data flags.
//
// (To cause this, hint a 3-byte instruction as data/inline-data, then
// hint the first byte of the instruction as code.)
// (To cause this, tag a 3-byte instruction as code-stop/inline-data, then
// tag the first byte of the instruction as code.)
mAnattribs[offset].IsInstructionStart = true;
mAnattribs[offset].Length = instrLen;
for (int i = offset; i < offset + instrLen; i++) {
@ -1113,12 +1115,12 @@ namespace SourceGen {
}
// Don't allow formatting of any bytes that are identified as instructions or
// were hinted by the user as something other than inline data. If the code
// were tagged by the user as something other than inline data. If the code
// analyzer comes crashing through later they'll just stomp on what we've done.
for (int i = offset; i < offset + length; i++) {
if (mTypeHints[i] != TypeHint.NoHint && mTypeHints[i] != TypeHint.InlineData) {
LogW(offset, "SIDF rej: already a hint at " + i.ToString("x6") +
" (" + mTypeHints[i] + ")");
if (mAnalyzerTags[i] != AnalyzerTag.None && mAnalyzerTags[i] != AnalyzerTag.InlineData) {
LogW(offset, "SIDF rej: already an atag at " + i.ToString("x6") +
" (" + mAnalyzerTags[i] + ")");
return false;
}
if (mAnattribs[offset].IsInstruction) {

View File

@ -60,9 +60,9 @@ namespace SourceGen {
public AddressMap AddrMap { get; private set; }
/// <summary>
/// Type hints. Default value is "no hint".
/// Analyzer tags. Default value is "none".
/// </summary>
public CodeAnalysis.TypeHint[] TypeHints { get; private set; }
public CodeAnalysis.AnalyzerTag[] AnalyzerTags { get; private set; }
/// <summary>
/// Status flag overrides. Default value is "all unspecified".
@ -272,8 +272,8 @@ namespace SourceGen {
AddrMap = new AddressMap(fileDataLen);
AddrMap.Set(0, 0x1000); // default load address to $1000; override later
// Default value is "no hint".
TypeHints = new CodeAnalysis.TypeHint[fileDataLen];
// Default value is "no tag".
AnalyzerTags = new CodeAnalysis.AnalyzerTag[fileDataLen];
// Default value is "unspecified" for all bits.
StatusFlagOverrides = new StatusFlags[fileDataLen];
@ -358,7 +358,7 @@ namespace SourceGen {
// Mark the first byte as code so we have something to do. This may get
// overridden later.
TypeHints[0] = CodeAnalysis.TypeHint.Code;
AnalyzerTags[0] = CodeAnalysis.AnalyzerTag.Code;
}
/// <summary>
@ -401,8 +401,8 @@ namespace SourceGen {
AddrMap.Set(2, loadAddr);
OperandFormats[0] = FormatDescriptor.Create(2, FormatDescriptor.Type.NumericLE,
FormatDescriptor.SubType.None);
TypeHints[0] = CodeAnalysis.TypeHint.NoHint;
TypeHints[2] = CodeAnalysis.TypeHint.Code;
AnalyzerTags[0] = CodeAnalysis.AnalyzerTag.None;
AnalyzerTags[2] = CodeAnalysis.AnalyzerTag.Code;
} else {
int loadAddr = SystemDefaults.GetLoadAddress(sysDef);
AddrMap.Set(0, loadAddr);
@ -832,7 +832,7 @@ namespace SourceGen {
reanalysisTimer.StartTask("CodeAnalysis.Analyze");
CodeAnalysis ca = new CodeAnalysis(mFileData, CpuDef, mAnattribs, AddrMap,
TypeHints, StatusFlagOverrides, ProjectProps.EntryFlags,
AnalyzerTags, StatusFlagOverrides, ProjectProps.EntryFlags,
ProjectProps.AnalysisParams, mScriptManager, debugLog);
ca.Analyze();
@ -987,10 +987,10 @@ namespace SourceGen {
/// </summary>
/// <remarks>
/// In an ideal world, this would be a trivial function. In practice it's possible for
/// all sorts of weird edge cases to arise, e.g. if you hint something as data, apply
/// formats, and then hint it as code, many strange things are possible. We don't want
/// to delete user data if it seems out of place, but we do want to ignore anything
/// that's going to confuse the source generator later on.
/// all sorts of weird edge cases to arise, e.g. if you put a code-stop flag, apply
/// formats, and then change it to code-start, many strange things are possible. We
/// don't want to delete user data if it seems out of place, but we do want to ignore
/// anything that's going to confuse the source generator later on.
///
/// Problem reports are written to a log (which is shown by the Analyzer Output
/// window) and the Problems list. Once the latter is better established we can
@ -1253,8 +1253,8 @@ namespace SourceGen {
/// <summary>
/// Removes user labels from the symbol table if they're in the middle of an
/// instruction or multi-byte data area. (Easy way to cause this: hint a 3-byte
/// instruction as data, add a label to the middle byte, remove hints.)
/// instruction or multi-byte data area. (Easy way to cause this: tag a 3-byte
/// instruction as data, add a label to the middle byte, remove atags.)
///
/// Call this after the code and data analysis passes have completed. Any
/// references to the hidden labels will just fall through. It will be possible
@ -1527,9 +1527,9 @@ namespace SourceGen {
try {
labelList.Add(attr.Symbol.Label, offset);
} catch (ArgumentException ex) {
// Duplicate UserLabel entries are stripped when projects are loaded,
// but it might be possible to cause this by hiding/unhiding a
// label (e.g. using hints to place it in the middle of an instruction).
// Duplicate UserLabel entries are stripped when projects are loaded, but
// it might be possible to cause this by hiding/unhiding a label (e.g.
// using a code start tag to place it in the middle of an instruction).
// Just ignore the duplicate.
Debug.WriteLine("Xref ignoring duplicate label '" + attr.Symbol.Label +
"': " + ex.Message);
@ -2166,9 +2166,9 @@ namespace SourceGen {
UndoableChange.ReanalysisScope.CodeAndData);
}
break;
case UndoableChange.ChangeType.SetTypeHint: {
case UndoableChange.ChangeType.SetAnalyzerTag: {
// Always requires full code+data re-analysis.
ApplyTypeHints((TypedRangeSet)oldValue, (TypedRangeSet)newValue);
ApplyAnalyzerTags((TypedRangeSet)oldValue, (TypedRangeSet)newValue);
// ignore affectedOffsets
Debug.Assert(uc.ReanalysisRequired ==
UndoableChange.ReanalysisScope.CodeAndData);
@ -2558,24 +2558,20 @@ namespace SourceGen {
/// <summary>
/// Applies the values in the set to the project hints.
/// Applies the values in the set to the project's atags.
/// </summary>
/// <param name="oldSet">Previous values; must match current contents.</param>
/// <param name="newSet">Values to apply.</param>
private void ApplyTypeHints(TypedRangeSet oldSet, TypedRangeSet newSet) {
CodeAnalysis.TypeHint[] hints = TypeHints;
private void ApplyAnalyzerTags(TypedRangeSet oldSet, TypedRangeSet newSet) {
CodeAnalysis.AnalyzerTag[] atags = AnalyzerTags;
foreach (TypedRangeSet.Tuple tuple in newSet) {
CodeAnalysis.TypeHint curType = hints[tuple.Value];
CodeAnalysis.AnalyzerTag curType = atags[tuple.Value];
if (!oldSet.GetType(tuple.Value, out int oldType) || oldType != (int)curType) {
Debug.WriteLine("Type mismatch at " + tuple.Value);
Debug.Assert(false);
}
//Debug.WriteLine("Set +" + tuple.Value.ToString("x6") + " to " +
// (CodeAnalysis.TypeHint)tuple.Type + " (was " +
// curType + ")");
hints[tuple.Value] = (CodeAnalysis.TypeHint)tuple.Type;
atags[tuple.Value] = (CodeAnalysis.AnalyzerTag)tuple.Type;
}
}

View File

@ -222,7 +222,7 @@ namespace SourceGen {
/// multiple offsets, this seems like reasonable behavior.
///
/// We can't precisely restore the selection in terms of which file offsets
/// are selected. If you select one byte and apply a code hint, we'll restore
/// are selected. If you select one byte and apply an analyzer tag, we'll restore
/// the selection to a line with 1-4 bytes. This gets weird if you hit "undo",
/// as you will then have 1-4 bytes selected rather than the original one. It
/// might be better to just clear the selection on "undo".
@ -291,7 +291,7 @@ namespace SourceGen {
continue;
}
Line line = lineList[i];
// Code hinting can transform code to data and vice-versa, so we
// Code start/stop tags can transform code to data and vice-versa, so we
// want the tag to reflect the fact that both could exist.
Line.Type lineType = line.LineType;
if (lineType == Line.Type.Code || lineType == Line.Type.Data) {
@ -317,7 +317,7 @@ namespace SourceGen {
// you do a sequence like:
// - Open a file that starts with a JMP followed by data.
// - Click on the blank line below the code, which has the code's offset,
// and select "remove hint". This causes the blank line to vanish,
// and select "remove atags". This causes the blank line to vanish,
// so the Restore() won't select anything.
// - Click "undo".
Debug.WriteLine("NOTE: no selection found");

View File

@ -2695,23 +2695,23 @@ namespace SourceGen {
cs.Add(uc);
}
// Apply code hints.
if (dlg.WantCodeHints) {
// Apply analyzer tags.
if (dlg.WantCodeStartPoints) {
TypedRangeSet newSet = new TypedRangeSet();
TypedRangeSet undoSet = new TypedRangeSet();
foreach (int offset in dlg.AllTargetOffsets) {
if (!mProject.GetAnattrib(offset).IsInstruction) {
CodeAnalysis.TypeHint oldType = mProject.TypeHints[offset];
if (oldType == CodeAnalysis.TypeHint.Code) {
CodeAnalysis.AnalyzerTag oldType = mProject.AnalyzerTags[offset];
if (oldType == CodeAnalysis.AnalyzerTag.Code) {
continue; // already set
}
undoSet.Add(offset, (int)oldType);
newSet.Add(offset, (int)CodeAnalysis.TypeHint.Code);
newSet.Add(offset, (int)CodeAnalysis.AnalyzerTag.Code);
}
}
if (newSet.Count != 0) {
cs.Add(UndoableChange.CreateTypeHintChange(undoSet, newSet));
cs.Add(UndoableChange.CreateAnalyzerTagChange(undoSet, newSet));
}
}
@ -2990,7 +2990,7 @@ namespace SourceGen {
} else if (uc.Type == UndoableChange.ChangeType.SetProjectProperties) {
// some chance it modified the EQU statements... jump there
offset = 0;
} else if (uc.Type == UndoableChange.ChangeType.SetTypeHint) {
} else if (uc.Type == UndoableChange.ChangeType.SetAnalyzerTag) {
TypedRangeSet newSet = (TypedRangeSet)uc.NewValue;
if (newSet.Count == 0) {
// unexpected
@ -3141,14 +3141,14 @@ namespace SourceGen {
public int mBlankLines;
public int mControlLines;
public int mCodeHints;
public int mDataHints;
public int mInlineDataHints;
public int mNoHints;
public int mCodeStartTags;
public int mCodeStopTags;
public int mInlineDataTags;
public int mNoTags;
};
/// <summary>
/// Gathers a count of different line types and hints that are currently selected.
/// Gathers a count of different line types and atags that are currently selected.
/// </summary>
/// <param name="singleLineIndex">If a single line is selected, pass the index in.
/// Otherwise, pass -1 to traverse the entire line list.</param>
@ -3156,9 +3156,9 @@ namespace SourceGen {
private EntityCounts GatherEntityCounts(int singleLineIndex) {
//DateTime startWhen = DateTime.Now;
int codeLines, dataLines, blankLines, controlLines;
int codeHints, dataHints, inlineDataHints, noHints;
int codeStartTags, codeStopTags, inlineDataTags, noTags;
codeLines = dataLines = blankLines = controlLines = 0;
codeHints = dataHints = inlineDataHints = noHints = 0;
codeStartTags = codeStopTags = inlineDataTags = noTags = 0;
int startIndex, endIndex;
if (singleLineIndex < 0) {
@ -3189,15 +3189,15 @@ namespace SourceGen {
break;
default:
// These are only editable as single-line items. We do allow mass
// code hint selection to include them (they will be ignored).
// atag selection to include them (they will be ignored).
// org, equ, rwid, long comment...
controlLines++;
break;
}
// A single line can span multiple offsets, each of which could have a
// different hint. Note the code/data hints are only applied to the first
// byte of each selected line, so we're not quite in sync with that.
// different analyzer tag. Note the code start/stop tags are only applied to the
// first byte of each selected line, so we're not quite in sync with that.
//
// For multi-line items, the OffsetSpan of the first item covers the entire
// item (it's the same for all Line instances), so we only want to do this for
@ -3205,18 +3205,18 @@ namespace SourceGen {
if (line.SubLineIndex == 0) {
for (int offset = line.FileOffset; offset < line.FileOffset + line.OffsetSpan;
offset++) {
switch (mProject.TypeHints[offset]) {
case CodeAnalysis.TypeHint.Code:
codeHints++;
switch (mProject.AnalyzerTags[offset]) {
case CodeAnalysis.AnalyzerTag.Code:
codeStartTags++;
break;
case CodeAnalysis.TypeHint.Data:
dataHints++;
case CodeAnalysis.AnalyzerTag.Data:
codeStopTags++;
break;
case CodeAnalysis.TypeHint.InlineData:
inlineDataHints++;
case CodeAnalysis.AnalyzerTag.InlineData:
inlineDataTags++;
break;
case CodeAnalysis.TypeHint.NoHint:
noHints++;
case CodeAnalysis.AnalyzerTag.None:
noTags++;
break;
default:
Debug.Assert(false);
@ -3235,10 +3235,10 @@ namespace SourceGen {
mDataLines = dataLines,
mBlankLines = blankLines,
mControlLines = controlLines,
mCodeHints = codeHints,
mDataHints = dataHints,
mInlineDataHints = inlineDataHints,
mNoHints = noHints
mCodeStartTags = codeStartTags,
mCodeStopTags = codeStopTags,
mInlineDataTags = inlineDataTags,
mNoTags = noTags
};
}
@ -3363,11 +3363,11 @@ namespace SourceGen {
}
/// <summary>
/// Handles the four Actions &gt; edit hint commands.
/// Handles the four analyzer tag commands.
/// </summary>
/// <param name="hint">Type of hint to apply.</param>
/// <param name="firstByteOnly">If set, only the first byte on each line is hinted.</param>
public void MarkAsType(CodeAnalysis.TypeHint hint, bool firstByteOnly) {
/// <param name="atag">Type of tag to apply.</param>
/// <param name="firstByteOnly">If set, only the first byte on each line is tagged.</param>
public void MarkAsType(CodeAnalysis.AnalyzerTag atag, bool firstByteOnly) {
RangeSet sel;
if (firstByteOnly) {
@ -3375,7 +3375,7 @@ namespace SourceGen {
foreach (int index in mMainWin.CodeDisplayList.SelectedIndices) {
int offset = CodeLineList[index].FileOffset;
if (offset >= 0) {
// Not interested in the header stuff for hinting.
// Ignore the header lines.
sel.Add(offset);
}
}
@ -3391,20 +3391,20 @@ namespace SourceGen {
// header comment
continue;
}
CodeAnalysis.TypeHint oldType = mProject.TypeHints[offset];
if (oldType == hint) {
CodeAnalysis.AnalyzerTag oldType = mProject.AnalyzerTags[offset];
if (oldType == atag) {
// no change, don't add to set
continue;
}
undoSet.Add(offset, (int)oldType);
newSet.Add(offset, (int)hint);
newSet.Add(offset, (int)atag);
}
if (newSet.Count == 0) {
Debug.WriteLine("No changes found (" + hint + ", " + sel.Count + " offsets)");
Debug.WriteLine("No changes found (" + atag + ", " + sel.Count + " offsets)");
return;
}
UndoableChange uc = UndoableChange.CreateTypeHintChange(undoSet, newSet);
UndoableChange uc = UndoableChange.CreateAnalyzerTagChange(undoSet, newSet);
ChangeSet cs = new ChangeSet(uc);
ApplyUndoableChanges(cs);
@ -3534,7 +3534,7 @@ namespace SourceGen {
/// We don't split based on existing data format items. That would make it impossible
/// to convert from (say) a collection of single bytes to a collection of double bytes
/// or a string. It should not be possible to select part of a formatted section,
/// unless the user has been playing weird games with type hints to get overlapping
/// unless the user has been playing weird games with analyzer tags to get overlapping
/// format descriptors.
///
/// The type values used in the TypedRangeSet may not be contiguous. They're only
@ -4070,17 +4070,17 @@ namespace SourceGen {
//sb.Append("DEBUG: opAddr=" + attr.OperandAddress.ToString("x4") +
// " opOff=" + attr.OperandOffset.ToString("x4") + "\r\n");
if (attr.IsHinted) {
if (attr.HasAnalyzerTag) {
sb.Append("\u2022 Analyzer Tags: ");
for (int i = 0; i < line.OffsetSpan; i++) {
switch (mProject.TypeHints[line.FileOffset + i]) {
case CodeAnalysis.TypeHint.Code:
switch (mProject.AnalyzerTags[line.FileOffset + i]) {
case CodeAnalysis.AnalyzerTag.Code:
sb.Append("S"); // S)tart
break;
case CodeAnalysis.TypeHint.Data:
case CodeAnalysis.AnalyzerTag.Data:
sb.Append("E"); // E)nd
break;
case CodeAnalysis.TypeHint.InlineData:
case CodeAnalysis.AnalyzerTag.InlineData:
sb.Append("I"); // I)nline
break;
default:
@ -4540,7 +4540,8 @@ namespace SourceGen {
}
// Make sure this is the start of an instruction or data item. (If you
// haven't finished hinting code, it's best to disable the string/fill finder.)
// haven't finished tagging code start points, it's best to disable the
// string/fill finder.)
Anattrib attr = mProject.GetAnattrib(offset);
if (!attr.IsStart) {
Debug.WriteLine("Found match at non-start +" + offset.ToString("x6") +

View File

@ -459,20 +459,20 @@ namespace SourceGen {
spf.AddressMap.Add(new SerAddressMap(ent));
}
// Reduce TypeHints to a collection of ranges. Output the type enum as a string
// so we're not tied to a specific value.
// Reduce analyzer tags (formerly known as "type hints") to a collection of ranges.
// Output the type enum as a string so we're not tied to a specific numeric value.
spf.TypeHints = new List<SerTypeHintRange>();
TypedRangeSet trs = new TypedRangeSet();
for (int i = 0; i < proj.TypeHints.Length; i++) {
trs.Add(i, (int)proj.TypeHints[i]);
for (int i = 0; i < proj.AnalyzerTags.Length; i++) {
trs.Add(i, (int)proj.AnalyzerTags[i]);
}
IEnumerator<TypedRangeSet.TypedRange> iter = trs.RangeListIterator;
while (iter.MoveNext()) {
if (iter.Current.Type == (int)CodeAnalysis.TypeHint.NoHint) {
if (iter.Current.Type == (int)CodeAnalysis.AnalyzerTag.None) {
continue;
}
spf.TypeHints.Add(new SerTypeHintRange(iter.Current.Low, iter.Current.High,
((CodeAnalysis.TypeHint)iter.Current.Type).ToString()));
((CodeAnalysis.AnalyzerTag)iter.Current.Type).ToString()));
}
// Convert StatusFlagOverrides to serializable form. Just write the state out
@ -672,26 +672,27 @@ namespace SourceGen {
proj.AddrMap.Set(addr.Offset, addr.Addr);
}
// Deserialize type hints. Default value in new array as NoHint, so we don't
// need to write those. They should not have been recorded in the file.
// Deserialize analyzer tags (formerly known as "type hints"). The default value
// for new array entries is None, so we don't need to write those. They should not
// have been recorded in the file.
foreach (SerTypeHintRange range in spf.TypeHints) {
if (range.Low < 0 || range.High >= spf.FileDataLength || range.Low > range.High) {
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_RANGE +
": " + Res.Strings.PROJECT_FIELD_TYPE_HINT +
": " + Res.Strings.PROJECT_FIELD_ANALYZER_TAG +
" +" + range.Low.ToString("x6") + " - +" + range.High.ToString("x6"));
continue;
}
CodeAnalysis.TypeHint hint;
CodeAnalysis.AnalyzerTag hint;
try {
hint = (CodeAnalysis.TypeHint) Enum.Parse(
typeof(CodeAnalysis.TypeHint), range.Hint);
hint = (CodeAnalysis.AnalyzerTag) Enum.Parse(
typeof(CodeAnalysis.AnalyzerTag), range.Hint);
} catch (ArgumentException) {
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_TYPE_HINT +
report.Add(FileLoadItem.Type.Warning, Res.Strings.ERR_BAD_ANALYZER_TAG +
": " + range.Hint);
continue;
}
for (int i = range.Low; i <= range.High; i++) {
proj.TypeHints[i] = hint;
proj.AnalyzerTags[i] = hint;
}
}

View File

@ -56,7 +56,7 @@ limitations under the License.
<system:String x:Key="str_ErrBadSymbolLabel">Malformed label in symbol</system:String>
<system:String x:Key="str_ErrBadSymbolSt">Unknown Source or Type in symbol</system:String>
<system:String x:Key="str_ErrBadSymrefPart">Bad symbol reference part</system:String>
<system:String x:Key="str_ErrBadTypeHint">Analyzer tag not recognized</system:String>
<system:String x:Key="str_ErrBadAnalyzerTag">Analyzer tag not recognized</system:String>
<system:String x:Key="str_ErrBadVisualizationFmt">Invalid visualization item: {0}</system:String>
<system:String x:Key="str_ErrBadVisualizationSetFmt">Invalid visualization set at +{0:x6}</system:String>
<system:String x:Key="str_ErrDirCreateFailedFmt">Unable to create directory {0}: {1}</system:String>
@ -162,7 +162,7 @@ limitations under the License.
<system:String x:Key="str_ProjectFieldOperandFormat">operand format</system:String>
<system:String x:Key="str_ProjectFieldRelocData">reloc data</system:String>
<system:String x:Key="str_ProjectFieldStatusFlags">status flag override</system:String>
<system:String x:Key="str_ProjectFieldTypeHint">analyzer tag</system:String>
<system:String x:Key="str_ProjectFieldAnalyzerTag">analyzer tag</system:String>
<system:String x:Key="str_ProjectFieldUserLabel">user-defined label</system:String>
<system:String x:Key="str_ProjectFromNewerApp">This project was created by a newer version of SourceGen. It may contain data that will be lost if the project is edited.</system:String>
<!--<system:String x:Key="str_RecentProjectLinkFmt">#{0}: {1}</system:String>-->

View File

@ -93,8 +93,8 @@ namespace SourceGen.Res {
(string)Application.Current.FindResource("str_ErrBadSymbolSt");
public static string ERR_BAD_SYMREF_PART =
(string)Application.Current.FindResource("str_ErrBadSymrefPart");
public static string ERR_BAD_TYPE_HINT =
(string)Application.Current.FindResource("str_ErrBadTypeHint");
public static string ERR_BAD_ANALYZER_TAG =
(string)Application.Current.FindResource("str_ErrBadAnalyzerTag");
public static string ERR_BAD_VISUALIZATION_FMT =
(string)Application.Current.FindResource("str_ErrBadVisualizationFmt");
public static string ERR_BAD_VISUALIZATION_SET_FMT =
@ -305,8 +305,8 @@ namespace SourceGen.Res {
(string)Application.Current.FindResource("str_ProjectFieldRelocData");
public static string PROJECT_FIELD_STATUS_FLAGS =
(string)Application.Current.FindResource("str_ProjectFieldStatusFlags");
public static string PROJECT_FIELD_TYPE_HINT =
(string)Application.Current.FindResource("str_ProjectFieldTypeHint");
public static string PROJECT_FIELD_ANALYZER_TAG =
(string)Application.Current.FindResource("str_ProjectFieldAnalyzerTag");
public static string PROJECT_FIELD_USER_LABEL =
(string)Application.Current.FindResource("str_ProjectFieldUserLabel");
public static string PROJECT_FROM_NEWER_APP =

View File

@ -404,7 +404,7 @@ namespace SourceGen.Tools.Omf {
uc = UndoableChange.CreateProjectPropertiesChange(proj.ProjectProps, newProps);
cs.Add(uc);
// TODO(someday): by default we apply a code hint to offset 0 of the first
// TODO(someday): by default we apply a code start tag to offset 0 of the first
// segment. The placement should take the segment's ENTRY into account.
Debug.WriteLine("Applying " + cs.Count + " changes");
@ -586,12 +586,12 @@ namespace SourceGen.Tools.Omf {
// It seems to be fairly common for jump table entries to not be referenced
// from the program, which can leave whole dynamic segments unreferenced. Set
// a code hint on the JML instruction.
undoSet.Add(jmlOffset, (int)CodeAnalysis.TypeHint.NoHint);
newSet.Add(jmlOffset, (int)CodeAnalysis.TypeHint.Code);
// a code start tag on the JML instruction.
undoSet.Add(jmlOffset, (int)CodeAnalysis.AnalyzerTag.None);
newSet.Add(jmlOffset, (int)CodeAnalysis.AnalyzerTag.Code);
}
UndoableChange uc = UndoableChange.CreateTypeHintChange(undoSet, newSet);
UndoableChange uc = UndoableChange.CreateAnalyzerTagChange(undoSet, newSet);
cs.Add(uc);
return true;

View File

@ -23,8 +23,8 @@ using CommonUtil;
*** When is a full (code+data) re-analysis required?
- Adding/removing/changing an address change (ORG directive). This has a significant impact
on the code analyzer, as blocks of code may become reachable or unreachable.
- Adding/removing/changing a type hint. These can affect whether a given offset is treated
as code, which can have a dramatic effect on code analysis (consider the offset 0 code hint).
- Adding/removing/changing an analyzer tag. These can affect whether a given offset is treated
as executable code, which can have a dramatic effect on code analysis.
- Adding/removing/changing a status flag override. This can affect whether a branch is
always taken or never taken, and the M/X flags affect instruction interpretation. (It may
be possible to do an "incremental" code analysis here, working from the point of the change
@ -83,8 +83,8 @@ namespace SourceGen {
// Adds, updates, or removes a data bank register value.
SetDataBank,
// Changes the type hint.
SetTypeHint,
// Changes the analyzer tag.
SetAnalyzerTag,
// Adds, updates, or removes a processor status flag override.
SetStatusFlagOverride,
@ -133,8 +133,8 @@ namespace SourceGen {
public ChangeType Type { get; private set; }
/// <summary>
/// The "root offset". For example, changing the type hint for a 4-byte
/// instruction from code to data will actually affect 4 offsets, but we
/// The "root offset". For example, changing the analyzer tag for a 4-byte
/// instruction from "start" to "stop" will actually affect 4 offsets, but we
/// only need to specify the root item.
/// </summary>
public int Offset { get; private set; }
@ -162,7 +162,7 @@ namespace SourceGen {
get {
switch (Type) {
case ChangeType.Dummy:
case ChangeType.SetTypeHint:
case ChangeType.SetAnalyzerTag:
case ChangeType.SetProjectProperties:
return false;
default:
@ -231,27 +231,27 @@ namespace SourceGen {
}
/// <summary>
/// Creates an UndoableChange for a type hint update. Rather than adding a
/// Creates an UndoableChange for an analyzer tag update. Rather than adding a
/// separate UndoableChange for each affected offset -- which could span the
/// entire file -- we use range sets to record the before/after state.
/// </summary>
/// <param name="undoSet">Current values.</param>
/// <param name="newSet">New values.</param>
/// <returns>Change record.</returns>
public static UndoableChange CreateTypeHintChange(TypedRangeSet undoSet,
public static UndoableChange CreateAnalyzerTagChange(TypedRangeSet undoSet,
TypedRangeSet newSet) {
Debug.Assert(undoSet != null && newSet != null);
if (newSet.Count == 0) {
Debug.WriteLine("Empty hint change?");
Debug.WriteLine("Empty atag change?");
}
UndoableChange uc = new UndoableChange();
uc.Type = ChangeType.SetTypeHint;
uc.Type = ChangeType.SetAnalyzerTag;
uc.Offset = -1;
uc.OldValue = undoSet;
uc.NewValue = newSet;
// Any hint change can affect whether something is treated as code.
// Any analyzer tag change can affect whether something is treated as code.
// Either we're deliberately setting it as code or non-code, or we're
// setting it to "no hint", which means the code analyzer gets
// setting it to "none", which means the code analyzer gets
// to make the decision now. This requires a full code+data re-analysis.
uc.ReanalysisRequired = ReanalysisScope.CodeAndData;
return uc;

View File

@ -619,7 +619,7 @@ namespace SourceGen.WpfGui {
}
// NOTE: it's entirely possible to have a weird format (e.g. string) if the
// instruction used to be hinted as data. Handle it gracefully.
// instruction used to be tagged as code-stop. Handle it gracefully.
switch (dfd.FormatType) {
case FormatDescriptor.Type.NumericLE:
switch (dfd.FormatSubType) {

View File

@ -116,7 +116,7 @@ limitations under the License.
<GroupBox Header="Options">
<StackPanel>
<CheckBox Content="Tag targets as code start points" Margin="0,4,0,0"
IsChecked="{Binding WantCodeHints}"/>
IsChecked="{Binding WantCodeStartPoints}"/>
</StackPanel>
</GroupBox>
</StackPanel>

View File

@ -64,16 +64,16 @@ namespace SourceGen.WpfGui {
private bool mIsSplitTable;
/// <summary>
/// If set, caller will add code entry hints to targets.
/// If set, caller will add code start points to targets.
/// </summary>
public bool WantCodeHints {
get { return mWantCodeHints; }
public bool WantCodeStartPoints {
get { return mWantCodeStartPoints; }
set {
mWantCodeHints = value;
mWantCodeStartPoints = value;
OnPropertyChanged();
}
}
private bool mWantCodeHints;
private bool mWantCodeStartPoints;
/// <summary>
/// Set to true to make the "incompatible with selection" message visible.

View File

@ -340,7 +340,7 @@ limitations under the License.
<CommandBinding Command="{StaticResource UndoCmd}"
CanExecute="CanUndo" Executed="UndoCmd_Executed"/>
<!-- must come after code hint Ctrl+H Ctrl+C -->
<!-- must come after analyzer tag Ctrl+H Ctrl+C def -->
<CommandBinding Command="Copy"
CanExecute="IsProjectOpen" Executed="CopyCmd_Executed"/>

View File

@ -1088,7 +1088,7 @@ namespace SourceGen.WpfGui {
}
MainController.EntityCounts counts = mMainCtrl.SelectionAnalysis.mEntityCounts;
e.CanExecute = (counts.mDataLines > 0 || counts.mCodeLines > 0) &&
(counts.mDataHints != 0 || counts.mInlineDataHints != 0 || counts.mNoHints != 0);
(counts.mCodeStopTags != 0 || counts.mInlineDataTags != 0 || counts.mNoTags != 0);
}
private void CanTagAsCodeStopPoint(object sender, CanExecuteRoutedEventArgs e) {
if (!IsProjectOpen()) {
@ -1097,7 +1097,7 @@ namespace SourceGen.WpfGui {
}
MainController.EntityCounts counts = mMainCtrl.SelectionAnalysis.mEntityCounts;
e.CanExecute = (counts.mDataLines > 0 || counts.mCodeLines > 0) &&
(counts.mCodeHints != 0 || counts.mInlineDataHints != 0 || counts.mNoHints != 0);
(counts.mCodeStartTags != 0 || counts.mInlineDataTags != 0 || counts.mNoTags != 0);
}
private void CanTagAsInlineData(object sender, CanExecuteRoutedEventArgs e) {
if (!IsProjectOpen()) {
@ -1106,7 +1106,7 @@ namespace SourceGen.WpfGui {
}
MainController.EntityCounts counts = mMainCtrl.SelectionAnalysis.mEntityCounts;
e.CanExecute = (counts.mDataLines > 0 || counts.mCodeLines > 0) &&
(counts.mCodeHints != 0 || counts.mDataHints != 0 || counts.mNoHints != 0);
(counts.mCodeStartTags != 0 || counts.mCodeStopTags != 0 || counts.mNoTags != 0);
}
private void CanRemoveAnalyzerTags(object sender, CanExecuteRoutedEventArgs e) {
if (!IsProjectOpen()) {
@ -1115,7 +1115,7 @@ namespace SourceGen.WpfGui {
}
MainController.EntityCounts counts = mMainCtrl.SelectionAnalysis.mEntityCounts;
e.CanExecute = (counts.mDataLines > 0 || counts.mCodeLines > 0) &&
(counts.mCodeHints != 0 || counts.mDataHints != 0 || counts.mInlineDataHints != 0);
(counts.mCodeStartTags != 0 || counts.mCodeStopTags != 0 || counts.mInlineDataTags != 0);
}
private void CanJumpToOperand(object sender, CanExecuteRoutedEventArgs e) {
@ -1285,17 +1285,17 @@ namespace SourceGen.WpfGui {
private void TagAsCodeStartPointCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("tag as code start point");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.Code, true);
mMainCtrl.MarkAsType(CodeAnalysis.AnalyzerTag.Code, true);
}
private void TagAsCodeStopPointCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("tag as code stop point");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.Data, true);
mMainCtrl.MarkAsType(CodeAnalysis.AnalyzerTag.Data, true);
}
private void TagAsInlineDataCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("tag as inline data");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.InlineData, false);
mMainCtrl.MarkAsType(CodeAnalysis.AnalyzerTag.InlineData, false);
}
private void JumpToOperandCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
@ -1345,7 +1345,7 @@ namespace SourceGen.WpfGui {
private void RemoveAnalyzerTagsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("remove atags");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.NoHint, false);
mMainCtrl.MarkAsType(CodeAnalysis.AnalyzerTag.None, false);
}
private void SaveCmd_Executed(object sender, ExecutedRoutedEventArgs e) {