/* * Main goals: * 1. No copies, ever. States are deposited directly to, and read directly from, one giant ring buffer. * As a consequence, there is no multi-threading because there is nothing to thread. * 2. Support for arbitrary and changeable state sizes. Frequency is calculated dynamically. * 3. No delta compression. Keep it simple. If there are cores that benefit heavily from delta compression, we should * maintain a separate rewinder alongside this one that is customized for those cores. */ public ZwinderBuffer(IRewindSettings settings) { if (settings == null) { throw new ArgumentException("ZwinderBuffer's settings cannot be null."); } long targetSize = settings.BufferSize * 1024 * 1024; if (settings.TargetFrameLength < 1) { throw new ArgumentOutOfRangeException(nameof(settings.TargetFrameLength)); } Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2)); _sizeMask = Size - 1; _backingStoreType = settings.BackingStore; switch (settings.BackingStore) { case IRewindSettings.BackingStoreType.Memory: { var buffer = new MemoryBlock((ulong)Size); buffer.Protect(buffer.Start, buffer.Size, MemoryBlock.Protection.RW); _disposables.Add(buffer); _backingStore = new MemoryViewStream(true, true, (long)buffer.Start, (long)buffer.Size); _disposables.Add(_backingStore); break; } case IRewindSettings.BackingStoreType.TempFile: { var filename = TempFileManager.GetTempFilename("ZwinderBuffer"); var filestream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose); filestream.SetLength(Size); _backingStore = filestream; _disposables.Add(filestream); break; } default: throw new ArgumentException("Unsupported store type for ZwinderBuffer."); } if (settings.UseFixedRewindInterval) { _fixedRewindInterval = true; _targetRewindInterval = settings.TargetRewindInterval; } else { _fixedRewindInterval = false; _targetFrameLength = settings.TargetFrameLength; } _allowOutOfOrderStates = settings.AllowOutOfOrderStates; _states = new StateInfo[STATEMASK + 1]; _useCompression = settings.UseCompression; }
/* * Main goals: * 1. No copies, ever. States are deposited directly to, and read directly from, one giant ring buffer. * As a consequence, there is no multi-threading because there is nothing to thread. * 2. Support for arbitrary and changeable state sizes. Frequency is calculated dynamically. * 3. No delta compression. Keep it simple. If there are cores that benefit heavily from delta compression, we should * maintain a separate rewinder alongside this one that is customized for those cores. */ public ZwinderBuffer(IRewindSettings settings) { long targetSize = settings.BufferSize * 1024 * 1024; if (settings.TargetFrameLength < 1) { throw new ArgumentOutOfRangeException(nameof(settings.TargetFrameLength)); } Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2)); _sizeMask = Size - 1; _buffer = new MemoryBlock((ulong)Size); _buffer.Protect(_buffer.Start, _buffer.Size, MemoryBlock.Protection.RW); _targetFrameLength = settings.TargetFrameLength; _states = new StateInfo[STATEMASK + 1]; _useCompression = settings.UseCompression; }
public ElfRunner(string filename, long heapsize, long sealedheapsize, long invisibleheapsize) { using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { _elfhash = WaterboxUtils.Hash(fs); } // todo: hack up this baby to take Streams _elf = ELFReader.Load <long>(filename); var loadsegs = _elf.Segments.Where(s => s.Type == SegmentType.Load); long orig_start = loadsegs.Min(s => s.Address); orig_start &= ~(Environment.SystemPageSize - 1); long orig_end = loadsegs.Max(s => s.Address + s.Size); if (HasRelocations()) { _base = new MemoryBlock((ulong)(orig_end - orig_start)); _loadoffset = (long)_base.Start - orig_start; Initialize(0); } else { Initialize((ulong)orig_start); _base = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start)); _loadoffset = 0; Enter(); } try { _disposeList.Add(_base); AddMemoryBlock(_base, "elf"); _base.Activate(); _base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.RW); foreach (var seg in loadsegs) { var data = seg.GetContents(); Marshal.Copy(data, 0, Z.SS(seg.Address + _loadoffset), data.Length); } RegisterSymbols(); ProcessRelocations(); _base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.R); foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0)) { if ((sec.Flags & SectionFlags.Executable) != 0) { _base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RX); } else if ((sec.Flags & SectionFlags.Writable) != 0) { _base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RW); } } ulong end = _base.End; if (heapsize > 0) { _heap = new Heap(GetHeapStart(end), (ulong)heapsize, "sbrk-heap"); _heap.Memory.Activate(); end = _heap.Memory.End; _disposeList.Add(_heap); AddMemoryBlock(_heap.Memory, "sbrk - heap"); } if (sealedheapsize > 0) { _sealedheap = new Heap(GetHeapStart(end), (ulong)sealedheapsize, "sealed-heap"); _sealedheap.Memory.Activate(); end = _sealedheap.Memory.End; _disposeList.Add(_sealedheap); AddMemoryBlock(_sealedheap.Memory, "sealed-heap"); } if (invisibleheapsize > 0) { _invisibleheap = new Heap(GetHeapStart(end), (ulong)invisibleheapsize, "invisible-heap"); _invisibleheap.Memory.Activate(); end = _invisibleheap.Memory.End; _disposeList.Add(_invisibleheap); AddMemoryBlock(_invisibleheap.Memory, "invisible-heap"); } ConnectAllClibPatches(); Console.WriteLine("Loaded {0}@{1:X16}", filename, _base.Start); foreach (var sec in _elf.Sections.Where(s => s.LoadAddress != 0)) { Console.WriteLine(" {0}@{1:X16}, size {2}", sec.Name.PadLeft(20), sec.LoadAddress + _loadoffset, sec.Size.ToString().PadLeft(12)); } PrintTopSavableSymbols(); } catch { Dispose(); throw; } finally { Exit(); } }
public PeWrapper(string moduleName, byte[] fileData, ulong destAddress) { ModuleName = moduleName; _pe = new PeFile(fileData); Size = _pe.ImageNtHeaders.OptionalHeader.SizeOfImage; Start = destAddress; if (Size < _pe.ImageSectionHeaders.Max(s => (ulong)s.VirtualSize + s.VirtualAddress)) { throw new InvalidOperationException("Image not Big Enough"); } _fileHash = WaterboxUtils.Hash(fileData); foreach (var s in _pe.ImageSectionHeaders) { ulong start = Start + s.VirtualAddress; ulong length = s.VirtualSize; MemoryBlock.Protection prot; var r = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_READ) != 0; var w = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_WRITE) != 0; var x = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0; if (w && x) { throw new InvalidOperationException("Write and Execute not allowed"); } prot = x ? MemoryBlock.Protection.RX : w ? MemoryBlock.Protection.RW : MemoryBlock.Protection.R; var section = new Section { // chop off possible null padding from name Name = Encoding.ASCII.GetString(s.Name, 0, (s.Name.Select((v, i) => new { v, i }).FirstOrDefault(a => a.v == 0) ?? new { v = (byte)0, i = s.Name.Length }).i), Start = start, Size = length, SavedSize = WaterboxUtils.AlignUp(length), R = r, W = w, X = x, Prot = prot, DiskStart = s.PointerToRawData, DiskSize = s.SizeOfRawData }; _sections.Add(section); _sectionsByName.Add(section.Name, section); } _sectionsByName.TryGetValue(".idata", out _imports); _sectionsByName.TryGetValue(".sealed", out _sealed); _sectionsByName.TryGetValue(".invis", out _invisible); // OK, NOW MOUNT LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase; Memory = new MemoryBlock(Start, Size); Memory.Activate(); Memory.Protect(Start, Size, MemoryBlock.Protection.RW); // copy headers Marshal.Copy(fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders); // copy sections foreach (var s in _sections) { ulong datalength = Math.Min(s.Size, s.DiskSize); Marshal.Copy(fileData, (int)s.DiskStart, Z.US(s.Start), (int)datalength); WaterboxUtils.ZeroMemory(Z.US(s.Start + datalength), (long)(s.SavedSize - datalength)); } // apply relocations var n32 = 0; var n64 = 0; foreach (var rel in _pe.ImageRelocationDirectory) { foreach (var to in rel.TypeOffsets) { ulong address = Start + rel.VirtualAddress + to.Offset; switch (to.Type) { // there are many other types of relocation specified, // but the only that are used is 0 (does nothing), 3 (32 bit standard), 10 (64 bit standard) case 3: // IMAGE_REL_BASED_HIGHLOW { byte[] tmp = new byte[4]; Marshal.Copy(Z.US(address), tmp, 0, 4); uint val = BitConverter.ToUInt32(tmp, 0); tmp = BitConverter.GetBytes((uint)(val + LoadOffset)); Marshal.Copy(tmp, 0, Z.US(address), 4); n32++; break; } case 10: // IMAGE_REL_BASED_DIR64 { byte[] tmp = new byte[8]; Marshal.Copy(Z.US(address), tmp, 0, 8); long val = BitConverter.ToInt64(tmp, 0); tmp = BitConverter.GetBytes(val + LoadOffset); Marshal.Copy(tmp, 0, Z.US(address), 8); n64++; break; } } } } if (IntPtr.Size == 8 && n32 > 0) { // check mcmodel, etc throw new InvalidOperationException("32 bit relocations found in 64 bit dll! This will fail."); } Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations"); ProtectMemory(); // publish exports EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint); foreach (var export in _pe.ExportedFunctions) { if (export.Name != null) { ExportsByName.Add(export.Name, Z.US(Start + export.Address)); } ExportsByOrdinal.Add(export.Ordinal, Z.US(Start + export.Address)); } // collect information about imports // NB: Hints are not the same as Ordinals foreach (var import in _pe.ImportedFunctions) { Dictionary <string, IntPtr> module; if (!ImportsByModule.TryGetValue(import.DLL, out module)) { module = new Dictionary <string, IntPtr>(); ImportsByModule.Add(import.DLL, module); } var dest = Start + import.Thunk; if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start) { throw new InvalidOperationException("Import record outside of .idata!"); } module.Add(import.Name, Z.US(dest)); } Section midipix; if (_sectionsByName.TryGetValue(".midipix", out midipix)) { var dataOffset = midipix.DiskStart; CtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x30)) + LoadOffset); DtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x38)) + LoadOffset); } Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}"); foreach (var s in _sections.OrderBy(s => s.Start)) { Console.WriteLine(" @{0:x16} {1}{2}{3} `{4}` {5} bytes", s.Start, s.R ? "R" : " ", s.W ? "W" : " ", s.X ? "X" : " ", s.Name, s.Size); } Console.WriteLine("GDB Symbol Load:"); var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}"; if (_sectionsByName.ContainsKey(".data")) { symload += $" -s .data {_sectionsByName[".data"].Start}"; } if (_sectionsByName.ContainsKey(".bss")) { symload += $" -s .bss {_sectionsByName[".bss"].Start}"; } Console.WriteLine(symload); }
/// <summary> /// load the PE into memory /// </summary> /// <param name="org">start address</param> private void Mount() { LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase; Memory = new MemoryBlock(Start, Size); Memory.Activate(); Memory.Protect(Start, Size, MemoryBlock.Protection.RW); // copy headers Marshal.Copy(_fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders); // copy sections foreach (var s in _sections) { ulong datalength = Math.Min(s.Size, s.DiskSize); Marshal.Copy(_fileData, (int)s.DiskStart, Z.US(s.Start), (int)datalength); WaterboxUtils.ZeroMemory(Z.US(s.Start + datalength), (long)(s.SavedSize - datalength)); } // apply relocations var n32 = 0; var n64 = 0; foreach (var rel in _pe.ImageRelocationDirectory) { foreach (var to in rel.TypeOffsets) { ulong address = Start + rel.VirtualAddress + to.Offset; switch (to.Type) { // there are many other types of relocation specified, // but the only that are used is 0 (does nothing), 3 (32 bit standard), 10 (64 bit standard) case 3: // IMAGE_REL_BASED_HIGHLOW { byte[] tmp = new byte[4]; Marshal.Copy(Z.US(address), tmp, 0, 4); uint val = BitConverter.ToUInt32(tmp, 0); tmp = BitConverter.GetBytes((uint)(val + LoadOffset)); Marshal.Copy(tmp, 0, Z.US(address), 4); n32++; break; } case 10: // IMAGE_REL_BASED_DIR64 { byte[] tmp = new byte[8]; Marshal.Copy(Z.US(address), tmp, 0, 8); long val = BitConverter.ToInt64(tmp, 0); tmp = BitConverter.GetBytes(val + LoadOffset); Marshal.Copy(tmp, 0, Z.US(address), 8); n64++; break; } } } } if (IntPtr.Size == 8 && n32 > 0) { // check mcmodel, etc throw new InvalidOperationException("32 bit relocations found in 64 bit dll! This will fail."); } Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations"); ProtectMemory(); // publish exports EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint); foreach (var export in _pe.ExportedFunctions) { if (export.Name != null) { ExportsByName.Add(export.Name, Z.US(Start + export.Address)); } ExportsByOrdinal.Add(export.Ordinal, Z.US(Start + export.Address)); } // collect information about imports // NB: Hints are not the same as Ordinals foreach (var import in _pe.ImportedFunctions) { Dictionary <string, IntPtr> module; if (!ImportsByModule.TryGetValue(import.DLL, out module)) { module = new Dictionary <string, IntPtr>(); ImportsByModule.Add(import.DLL, module); } var dest = Start + import.Thunk; if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start) { throw new InvalidOperationException("Import record outside of .idata!"); } module.Add(import.Name, Z.US(dest)); } Section midipix; if (_sectionsByName.TryGetValue(".midipix", out midipix)) { var dataOffset = midipix.DiskStart; CtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x30)) + LoadOffset); DtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x38)) + LoadOffset); } Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}"); foreach (var s in _sections.OrderBy(s => s.Start)) { Console.WriteLine(" @{0:x16} {1}{2}{3} `{4}` {5} bytes", s.Start, s.R ? "R" : " ", s.W ? "W" : " ", s.X ? "X" : " ", s.Name, s.Size); } Console.WriteLine("GDB Symbol Load:"); var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}"; if (_sectionsByName.ContainsKey(".data")) { symload += $" -s .data {_sectionsByName[".data"].Start}"; } if (_sectionsByName.ContainsKey(".bss")) { symload += $" -s .bss {_sectionsByName[".bss"].Start}"; } Console.WriteLine(symload); }