using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.IO; namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { /* * how to use: * 0) get https://code.google.com/p/pdbparse/ * 1) set modulename to the name of the dll file. * 2) set symbolname to the name of a file that you produced by executing the following command: * pdb_print_gvars.py [module pdb file] 0x00000000 > [output file] * 3) set start to an address (relative to the beginning of the dll) to start scanning * 4) set length to the byte length of the scan area * 5) instantiate a GenDbWind, and use it to control the scanner while you manipulate the dll into various configurations. * * ideas for modification: * 1) unhardcode config parameters and allow modifying them through the interface * 2) read section sizes and positions from the dll itself instead of the start\length params * 3) support an ignore list of symbols */ public class GenDbgHlp : IDisposable { private static class Win32 { [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [DllImport("kernel32.dll")] public static extern bool FreeLibrary(IntPtr hModule); } // config const string modulename = "libgenplusgx.dll"; const string symbolname = @"D:\encodes\bizhawksrc\genplus-gx\libretro\msvc\Debug\vars.txt"; const int start = 0x0c7d8000 - 0x0c540000; const int length = 0x01082000; bool disposed = false; public void Dispose() { if (!disposed) { Win32.FreeLibrary(DllBase); DllBase = IntPtr.Zero; disposed = true; } } IntPtr DllBase; List SymbolsByAddr = new List(); Dictionary SymbolsByName = new Dictionary(); byte[][] data = new byte[10][]; public void SaveState(int statenum) { if (disposed) throw new ObjectDisposedException(this.GetType().ToString()); if (data[statenum] == null) data[statenum] = new byte[length]; Marshal.Copy(DllBase + start, data[statenum], 0, length); Console.WriteLine("State {0} saved", statenum); } unsafe public void Cmp(int statex, int statey) { if (disposed) throw new ObjectDisposedException(this.GetType().ToString()); List> bads = new List>(); byte[] x = data[statex]; byte[] y = data[statey]; if (x == null || y == null) { Console.WriteLine("Missing State!"); return; } bool inrange = false; int startsec = 0; fixed (byte* p0 = &x[0]) fixed (byte* p1 = &y[0]) { for (int i = 0; i < length; i++) { if (!inrange) { if (p0[i] != p1[i]) { startsec = i; inrange = true; } } else { if (p0[i] == p1[i]) { bads.Add(new Tuple(startsec, i)); inrange = false; } } } } if (inrange) bads.Add(new Tuple(startsec, length)); for (int i = 0; i < bads.Count; i++) { IntPtr addr = (IntPtr)(bads[i].Item1 + start); int len = bads[i].Item2 - bads[i].Item1; var ss = Find(addr, len); Console.WriteLine("0x{0:X8}[0x{1}]", (int)addr, len); foreach (var sym in ss) Console.WriteLine(sym); Console.WriteLine(); } if (bads.Count == 0) Console.WriteLine("Clean!"); } public GenDbgHlp() { using (StreamReader sr = new StreamReader(symbolname)) { string line; while ((line = sr.ReadLine()) != null) { Symbol sym = Symbol.FromString(line); SymbolsByAddr.Add(sym); SymbolsByName.Add(sym.name, sym); } SymbolsByAddr.Sort(); } DllBase = Win32.LoadLibrary(modulename); if (DllBase == IntPtr.Zero) throw new Exception(); } public List Find(IntPtr addr, int length) { if (disposed) throw new ObjectDisposedException(this.GetType().ToString()); Symbol min = new Symbol { addr = addr }; Symbol max = new Symbol { addr = addr + length }; int minidx = SymbolsByAddr.BinarySearch(min); if (minidx < 0) { minidx = ~minidx; // inexact matches return the first larger value, so find the next smallset one if (minidx > 0) minidx--; } int maxidx = SymbolsByAddr.BinarySearch(max); if (maxidx < 0) { maxidx = ~maxidx; if (maxidx > 0) maxidx--; } return SymbolsByAddr.GetRange(minidx, maxidx - minidx + 1); } public struct Symbol : IComparable { public IntPtr addr; public string section; public string name; public static Symbol FromString(string s) { string[] ss = s.Split(','); if (ss.Length != 4) throw new Exception(); if (!ss[1].StartsWith("0x")) throw new Exception(); Symbol ret = new Symbol { addr = (IntPtr)int.Parse(ss[1].Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier), section = ss[3], name = ss[0] }; return ret; } public int CompareTo(Symbol other) { return (int)this.addr - (int)other.addr; } public override string ToString() { return string.Format("0x{0:X8} {1} ({2})", (int)addr, name, section); } } } }