/// <summary> /// Adds one or more entries to the address map for the specified segment. /// </summary> private static void AddAddressEntries(DisasmProject proj, SegmentMapEntry ent, int bufOffset, ChangeSet cs) { int addr = ent.Address; int segRem = ent.Segment.Length; while (true) { // Generate an ORG directive. int origAddr = proj.AddrMap.Get(bufOffset); UndoableChange uc = UndoableChange.CreateAddressChange(bufOffset, origAddr, addr); cs.Add(uc); // Compare amount of space in this bank to amount left in segment. int bankRem = 0x00010000 - (addr & 0xffff); if (bankRem > segRem) { // All done, bail. break; } // Advance to start of next bank. addr += bankRem; Debug.Assert((addr & 0x0000ffff) == 0); bufOffset += bankRem; segRem -= bankRem; Debug.WriteLine("Adding additional ORG at " + addr); } }
private void AddHeaderComment(DisasmProject proj, ChangeSet cs) { // Add header comment. StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format(Res.Strings.DEFAULT_HEADER_COMMENT_FMT, App.ProgramVersion)); sb.AppendLine(); foreach (SegmentMapEntry ent in mSegmentMap) { if (ent == null) { continue; } string segCmt = string.Format(Res.Strings.OMF_SEG_HDR_COMMENT_FMT, ent.Segment.SegNum, ent.Segment.Kind, ent.Segment.SegName, mFormatter.FormatAddress(ent.Address, true), ent.Segment.Length); sb.AppendLine(segCmt); } UndoableChange uc = UndoableChange.CreateLongCommentChange( LineListGen.Line.HEADER_COMMENT_OFFSET, null, new MultiLineComment(sb.ToString())); cs.Add(uc); }
public static void AddAction(UndoableChange action) { redoStack.Clear(); undoStack.Push(action); Debug.Log("" + undoStack.Count); }
public static void AddBoxAction(UndoableChange action) { undoBoxes.Push(action); }
/// <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); }
private bool GenerateDataAndProject() { // Sum up the segment lengths to get the total project size. int totalLen = 0; foreach (SegmentMapEntry ent in mSegmentMap) { if (ent == null) { continue; } totalLen += ent.Segment.Length; } Debug.WriteLine("Total length of loaded binary is " + totalLen); byte[] data = new byte[totalLen]; // Create the project object. DisasmProject proj = new DisasmProject(); proj.Initialize(data.Length); // Try to get the Apple IIgs system definition. This is fragile, because it // relies on the name in the JSON file, but it's optional. (If the default CPU // type stops being 65816, we should be sure to set that here.) try { // TODO(maybe): encapsulate this somewhere else string sysDefsPath = RuntimeDataAccess.GetPathName("SystemDefs.json"); SystemDefSet sds = SystemDefSet.ReadFile(sysDefsPath); SystemDef sd = sds.FindEntryByName(IIGS_SYSTEM_DEF); if (sd != null) { proj.ApplySystemDef(sd); } else { Debug.WriteLine("Unable to find Apple IIgs system definition"); } } catch (Exception) { // never mind Debug.WriteLine("Failed to apply Apple IIgs system definition"); } ChangeSet cs = new ChangeSet(mSegmentMap.Count * 2); AddHeaderComment(proj, cs); UndoableChange uc; // Load the segments, and add entries to the project. int bufOffset = 0; foreach (SegmentMapEntry ent in mSegmentMap) { if (ent == null) { continue; } if (ent.Segment.Kind == OmfSegment.SegmentKind.JumpTable) { if (!RelocJumpTable(ent, data, bufOffset, cs)) { // Could treat this as non-fatal, but it really ought to work. Debug.WriteLine("Jump Table reloc failed"); return(false); } } else { // Perform relocation. if (!RelocSegment(ent, data, bufOffset)) { return(false); } } // Add one or more address entries. (Normally one, but data segments // can straddle multiple pages.) AddAddressEntries(proj, ent, bufOffset, cs); if ((mFlags & Flags.AddNotes) != 0) { // Add a comment identifying the segment and its attributes. string segCmt = string.Format(Res.Strings.OMF_SEG_COMMENT_FMT, ent.Segment.SegNum, ent.Segment.Kind, ent.Segment.Attrs, ent.Segment.SegName); uc = UndoableChange.CreateLongCommentChange(bufOffset, null, new MultiLineComment(segCmt)); cs.Add(uc); // Add a note identifying the segment. string segNote = string.Format(Res.Strings.OMF_SEG_NOTE_FMT, ent.Segment.SegNum, mFormatter.FormatAddress(ent.Address, true), ent.Segment.SegName); uc = UndoableChange.CreateNoteChange(bufOffset, null, new MultiLineComment(segNote)); cs.Add(uc); } bufOffset += ent.Segment.Length; } proj.PrepForNew(data, "new_proj"); foreach (KeyValuePair <int, DisasmProject.RelocData> kvp in mRelocData) { proj.RelocList.Add(kvp.Key, kvp.Value); } // Enable "use reloc" in the analysis parameters. ProjectProperties newProps = new ProjectProperties(proj.ProjectProps); newProps.AnalysisParams.UseRelocData = true; uc = UndoableChange.CreateProjectPropertiesChange(proj.ProjectProps, newProps); cs.Add(uc); // 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"); proj.ApplyChanges(cs, false, out _); mLoadedData = data; mNewProject = proj; return(true); }