public FormatSplitAddress(DisasmProject project, TypedRangeSet selection, Formatter formatter) { InitializeComponent(); mProject = project; mFormatter = formatter; mSelection = selection; mOutputReady = false; }
public FormatAddressTable(Window owner, DisasmProject project, TypedRangeSet selection, Formatter formatter) { InitializeComponent(); Owner = owner; DataContext = this; mProject = project; mFormatter = formatter; mSelection = selection; IsValid = false; OutputPreviewList = new ObservableCollection <OutputPreviewItem>(); }
/// <summary> /// Creates an UndoableChange for a type hint 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, TypedRangeSet newSet) { if (newSet.Count == 0) { Debug.WriteLine("Empty hint change?"); } UndoableChange uc = new UndoableChange(); uc.Type = ChangeType.SetTypeHint; uc.Offset = -1; uc.OldValue = undoSet; uc.NewValue = newSet; // Any hint 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 // to make the decision now. This requires a full code+data re-analysis. uc.ReanalysisRequired = ReanalysisScope.CodeAndData; return(uc); }
/// <summary> /// Serializes a DisasmProject into an augmented JSON string. /// </summary> /// <param name="proj">Project to serialize.</param> /// <returns>Augmented JSON string.</returns> public static string SerializeProject(DisasmProject proj) { StringBuilder sb = new StringBuilder(); sb.Append(MAGIC); // augment with version string, which will be stripped sb.Append("\r\n"); // will be ignored by deserializer; might get converted to \n SerializableProjectFile1 spf = new SerializableProjectFile1(); spf._ContentVersion = ProjectFile.CONTENT_VERSION; Debug.Assert(proj.FileDataLength == proj.FileData.Length); spf.FileDataLength = proj.FileDataLength; spf.FileDataCrc32 = (int)proj.FileDataCrc32; // Convert AddressMap to serializable form. spf.AddressMap = new List <SerAddressMap>(); foreach (AddressMap.AddressMapEntry ent in proj.AddrMap) { 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. 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]); } IEnumerator <TypedRangeSet.TypedRange> iter = trs.RangeListIterator; while (iter.MoveNext()) { if (iter.Current.Type == (int)CodeAnalysis.TypeHint.NoHint) { continue; } spf.TypeHints.Add(new SerTypeHintRange(iter.Current.Low, iter.Current.High, ((CodeAnalysis.TypeHint)iter.Current.Type).ToString())); } // Convert StatusFlagOverrides to serializable form. Just write the state out // as an integer... not expecting it to change. If it does, we can convert. spf.StatusFlagOverrides = new Dictionary <string, int>(); for (int i = 0; i < proj.StatusFlagOverrides.Length; i++) { if (proj.StatusFlagOverrides[i] == Asm65.StatusFlags.DefaultValue) { continue; } spf.StatusFlagOverrides.Add(i.ToString(), proj.StatusFlagOverrides[i].AsInt); } // Convert Comments to serializable form. spf.Comments = new Dictionary <string, string>(); for (int i = 0; i < proj.Comments.Length; i++) { if (string.IsNullOrEmpty(proj.Comments[i])) { continue; } spf.Comments.Add(i.ToString(), proj.Comments[i]); } // Convert multi-line comments to serializable form. spf.LongComments = new Dictionary <string, SerMultiLineComment>(); foreach (KeyValuePair <int, MultiLineComment> kvp in proj.LongComments) { spf.LongComments.Add(kvp.Key.ToString(), new SerMultiLineComment(kvp.Value)); } // Convert multi-line notes to serializable form. spf.Notes = new Dictionary <string, SerMultiLineComment>(); foreach (KeyValuePair <int, MultiLineComment> kvp in proj.Notes) { spf.Notes.Add(kvp.Key.ToString(), new SerMultiLineComment(kvp.Value)); } // Convert user-defined labels to serializable form. spf.UserLabels = new Dictionary <string, SerSymbol>(); foreach (KeyValuePair <int, Symbol> kvp in proj.UserLabels) { spf.UserLabels.Add(kvp.Key.ToString(), new SerSymbol(kvp.Value)); } // Convert operand and data item format descriptors to serializable form. spf.OperandFormats = new Dictionary <string, SerFormatDescriptor>(); foreach (KeyValuePair <int, FormatDescriptor> kvp in proj.OperandFormats) { spf.OperandFormats.Add(kvp.Key.ToString(), new SerFormatDescriptor(kvp.Value)); } spf.ProjectProps = new SerProjectProperties(proj.ProjectProps); JavaScriptSerializer ser = new JavaScriptSerializer(); string cereal = ser.Serialize(spf); sb.Append(cereal); // Stick a linefeed at the end. Makes git happier. sb.Append("\r\n"); return(sb.ToString()); }
/// <summary> /// Edits the data file, essentially putting the jump table entries into the /// "loaded" state. /// </summary> /// <remarks> /// We don't use ent.Segment.Relocs, as that is expected to be empty. /// </remarks> private bool RelocJumpTable(SegmentMapEntry ent, byte[] data, int bufOffset, ChangeSet cs) { const int ENTRY_LEN = 14; if (ent.Segment.Relocs.Count != 0) { Debug.WriteLine("WEIRD: jump table has reloc data?"); } byte[] srcData = ent.Segment.GetConstData(); Array.Copy(srcData, 0, data, bufOffset, srcData.Length); // For no documented reason, jump tables start with 8 zero bytes. for (int i = 0; i < 8; i++) { if (data[bufOffset + i] != 0) { Debug.WriteLine("JumpTab: missing 8-byte header"); return(false); } } TypedRangeSet newSet = new TypedRangeSet(); TypedRangeSet undoSet = new TypedRangeSet(); for (int i = 8; i + 4 <= ent.Segment.Length; i += ENTRY_LEN) { //int userId = RawData.GetWord(data, bufOffset + i, 2, false); int fileNum = RawData.GetWord(data, bufOffset + i + 2, 2, false); if (fileNum == 0) { // A zero file number indicates end of table. Debug.WriteLine("JumpTab: found fileNum=0 at offset " + i + ", len=" + ent.Segment.Length); break; } else if (fileNum != 1) { // External file, ignore entry. Debug.WriteLine("JumpTab: ignoring entry with FileNum=" + fileNum); continue; } else if (i + ENTRY_LEN > ent.Segment.Length) { // Make sure the rest fits. Debug.WriteLine("JumpTab: overran buffer"); return(false); } // Note: segment might end right after FileNum, so don't try to read further // until we've confirmed that FileNum != 0. int segNum = RawData.GetWord(data, bufOffset + i + 4, 2, false); int segOff = RawData.GetWord(data, bufOffset + i + 6, 4, false); if (segNum < 0 || segNum >= mSegmentMap.Count || mSegmentMap[segNum] == null) { Debug.WriteLine("JumpTab: invalid SegNum=" + segNum); return(false); } if (data[bufOffset + i + 10] != 0x22) { Debug.WriteLine("JumpTab: did not find expected JSL at off=" + i); return(false); } int addr = mSegmentMap[segNum].Address + segOff; int jmlOffset = bufOffset + i + 10; data[jmlOffset] = 0x5c; // JML data[jmlOffset + 1] = (byte)addr; data[jmlOffset + 2] = (byte)(addr >> 8); data[jmlOffset + 3] = (byte)(addr >> 16); //Debug.WriteLine("JumpTab: off=" + i + " -> " + // mFormatter.FormatAddress(addr, true)); // 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 start tag on the JML instruction. undoSet.Add(jmlOffset, (int)CodeAnalysis.AnalyzerTag.None); newSet.Add(jmlOffset, (int)CodeAnalysis.AnalyzerTag.Code); } UndoableChange uc = UndoableChange.CreateAnalyzerTagChange(undoSet, newSet); cs.Add(uc); return(true); }