diff --git a/data/resources/StringResources.resx b/data/resources/StringResources.resx index f29cd9261e..c4f3dcf887 100644 --- a/data/resources/StringResources.resx +++ b/data/resources/StringResources.resx @@ -5735,7 +5735,16 @@ Microsoft.Tools.WindowsInstallerXml.Extensions.NetFxCompiler, WixNetFxExtension< Jump to address: - Refresh + Refresh current addresses + + + Next virtual addresses + + + The address {0} was not found! + + + Previous virtual addresses Parallel Stacks diff --git a/data/resources/image/BitmapResources/BitmapResources.res b/data/resources/image/BitmapResources/BitmapResources.res index 3e8469ea86..2604ffecaf 100644 --- a/data/resources/image/BitmapResources/BitmapResources.res +++ b/data/resources/image/BitmapResources/BitmapResources.res @@ -47,7 +47,9 @@ OutputPad.Toolbar.ClearOutputWindow = OutputPadIcons\ClearOutputWindow.png OutputPad.Toolbar.ToggleWordWrap = OutputPadIcons\ToggleWordWrap.png #Memory pad -MemoryPad.Icon = PadIcons\memory.png +MemoryPad.Icon = PadIcons\memory.png +MemoryPad.NextMemoryIcon = PadIcons\nextmemory.png +MemoryPad.PreviousMemoryIcon = PadIcons\previousmemory.png Icons.16x16.OpenFolderBitmap = ProjectBrowserIcons\Folder.Open.png Icons.16x16.ClosedFolderBitmap = ProjectBrowserIcons\Folder.Closed.png diff --git a/data/resources/image/BitmapResources/PadIcons/NextMemory.png b/data/resources/image/BitmapResources/PadIcons/NextMemory.png new file mode 100644 index 0000000000..5f62ce83c8 Binary files /dev/null and b/data/resources/image/BitmapResources/PadIcons/NextMemory.png differ diff --git a/data/resources/image/BitmapResources/PadIcons/PreviousMemory.png b/data/resources/image/BitmapResources/PadIcons/PreviousMemory.png new file mode 100644 index 0000000000..9874eee748 Binary files /dev/null and b/data/resources/image/BitmapResources/PadIcons/PreviousMemory.png differ diff --git a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin index 28c0df125a..b300cf7f33 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin +++ b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin @@ -199,14 +199,32 @@ - - - + + + + + + + class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshAddressCommand"/> diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs index 8b37bbffb0..58bc7e716d 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs @@ -40,9 +40,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads } } - public sealed class RefreshMemoryCommand : AbstractCommand + public abstract class ItemMemoryCommand : AbstractCommand { - MemoryPad pad; + protected MemoryPad pad; protected override void OnOwnerChanged(EventArgs e) { @@ -52,13 +52,38 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads base.OnOwnerChanged(e); } - + } + + public sealed class RefreshAddressCommand : ItemMemoryCommand + { + public override void Run() + { + if (this.pad == null) + return; + + this.pad.Refresh(); + } + } + + public sealed class NextAddressCommand : ItemMemoryCommand + { + public override void Run() + { + if (this.pad == null) + return; + + this.pad.MoveToNextAddress(); + } + } + + public sealed class PreviousAddressCommand : ItemMemoryCommand + { public override void Run() { if (this.pad == null) return; - this.pad.Refresh(true); + this.pad.MoveToPreviousAddress(); } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs index 1ba1f5735d..1d6a369c4a 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs @@ -18,11 +18,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads { public sealed class MemoryPad : DebuggerPad { - Dictionary addressesMapping = new Dictionary(); + int currentAddressIndex; ConsoleControl console; int addressStep = 16; Process debuggedProcess; + List> memoryAddresses = new List>(); + Dictionary addressesMapping = new Dictionary(); public MemoryPad() { @@ -40,13 +42,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads protected override void SelectProcess(Process process) { - if (debuggedProcess != null) { - debuggedProcess.Paused -= OnProcessPaused; - } + if (process == null) + return; + debuggedProcess = process; - if (debuggedProcess != null) { - debuggedProcess.Paused += OnProcessPaused; - } + memoryAddresses = debuggedProcess.GetMemoryAddresses(); + currentAddressIndex = 0; } public override void RefreshPad() @@ -62,16 +63,33 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads address = address.Substring(2); long addr = Int64.Parse(address, NumberStyles.AllowHexSpecifier); - long mod = addr % addressStep; + // find index for the address or the near addess + currentAddressIndex = memoryAddresses.Search(addr); + if (currentAddressIndex == -1) { + MessageService.ShowMessage( + string.Format(ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad.AddressNotFound"), address), + ResourceService.GetString("MainWindow.Windows.Debug.MemoryPad")); + + currentAddressIndex = 0; + return; + } + + // refresh pad + Refresh(); + + // find line + long mod = addr % addressStep; int line; if (addressesMapping.ContainsKey(addr - mod)) line = addressesMapping[addr - mod]; else line = 1; - + + // jump console.SelectText(line, 0, 8); console.JumpToLine(line); + } catch (System.Exception ex) { #if DEBUG LoggingService.Error(ex.Message); @@ -79,34 +97,33 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads } } - public void Refresh(bool force = false) + public void Refresh() { if (debuggedProcess == null || debugger.IsProcessRunning) return; - if (!force && addressesMapping.Count > 0) + if (memoryAddresses.Count == 0) return; - if (force) { - addressesMapping.Clear(); - console.Clear(); - } + console.Clear();addressesMapping.Clear(); - long address; - byte[] memory = debuggedProcess.ReadProcessMemory(out address); + // get current address + var item = memoryAddresses[currentAddressIndex]; + long address = item.Item1; + long size = item.Item2; - if (memory == null) - return; + byte[] memory = debuggedProcess.ReadProcessMemory(address, size); + System.Diagnostics.Debug.Assert(memory != null); - int index = 0; int div = memory.Length / addressStep; int mod = memory.Length % addressStep; + int index = 0; while (index < div) { StringBuilder sb = new StringBuilder(); addressesMapping.Add(address, index + 1); // write address - sb.Append(address.ToString("X8"));address += addressStep; + sb.Append(address.ToString("X8")); address += (long)addressStep; sb.Append(" "); // write bytes @@ -121,13 +138,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads string s = sb1.ToString(); s = Regex.Replace(s, @"\r\n", string.Empty); s = Regex.Replace(s, @"\n", string.Empty); - s = Regex.Replace(s, @"\r", string.Empty); + s = Regex.Replace(s, @"\r", string.Empty); sb.Append(s); sb.Append(Environment.NewLine); // start writing in console console.Append(sb.ToString()); - index++; } @@ -151,7 +167,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads string s = sb1.ToString(); s = Regex.Replace(s, @"\r\n", string.Empty); s = Regex.Replace(s, @"\n", string.Empty); - s = Regex.Replace(s, @"\r", string.Empty); + s = Regex.Replace(s, @"\r", string.Empty); sb.Append(s); sb.Append(Environment.NewLine); @@ -161,9 +177,46 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads } } - private void OnProcessPaused(object sender, ProcessEventArgs e) + public void MoveToPreviousAddress() { + if (debuggedProcess == null || debugger.IsProcessRunning) + return; + + if (currentAddressIndex == 0) + return; + + currentAddressIndex--; + Refresh(); + } + + public void MoveToNextAddress() + { + if (debuggedProcess == null || debugger.IsProcessRunning) + return; + + if (currentAddressIndex == memoryAddresses.Count) + return; + + currentAddressIndex++; Refresh(); } } + + internal static class MemoryPadExtensions + { + internal static int Search(this List> source, long item1) + { + if (source == null) + throw new NullReferenceException("Source is null!"); + + for (int i = 0; i < source.Count - 1; i++) { + if (source[i + 1].Item1 < item1) + continue; + + return i; + } + + return -1; + } + } } diff --git a/src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs b/src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs index 5c99cf079c..cfa343243b 100644 --- a/src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs +++ b/src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs @@ -4,6 +4,7 @@ #pragma warning disable 1591 using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; @@ -38,6 +39,62 @@ namespace Debugger.Interop Synchronize = 0x00100000 } + [StructLayout(LayoutKind.Sequential)] + public struct SYSTEM_INFO + { + internal _PROCESSOR_INFO_UNION uProcessorInfo; + public uint dwPageSize; + public IntPtr lpMinimumApplicationAddress; + public IntPtr lpMaximumApplicationAddress; + public IntPtr dwActiveProcessorMask; + public uint dwNumberOfProcessors; + public uint dwProcessorType; + public uint dwAllocationGranularity; + public ushort dwProcessorLevel; + public ushort dwProcessorRevision; + } + + [StructLayout(LayoutKind.Explicit)] + public struct _PROCESSOR_INFO_UNION + { + [FieldOffset(0)] + internal uint dwOemId; + [FieldOffset(0)] + internal ushort wProcessorArchitecture; + [FieldOffset(2)] + internal ushort wReserved; + } + + [Flags] + public enum AllocationType + { + Commit = 0x1000, + Reserve = 0x2000, + Decommit = 0x4000, + Release = 0x8000, + Reset = 0x80000, + Physical = 0x400000, + TopDown = 0x100000, + WriteWatch = 0x200000, + LargePages = 0x20000000 + } + + [Flags] + public enum MemoryProtection + { + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + GuardModifierflag = 0x100, + NoCacheModifierflag = 0x200, + WriteCombineModifierflag = 0x400 + } + public static class NativeMethods { [DllImport("kernel32.dll")] @@ -63,7 +120,7 @@ namespace Debugger.Interop [DllImport("kernel32.dll", SetLastError = true)] public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, - UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); + UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool ReadProcessMemory( @@ -74,45 +131,59 @@ namespace Debugger.Interop out int lpNumberOfBytesRead ); - public static byte[] ReadProcessMemory(this Process process, out long baseAddress) + [DllImport("kernel32.dll", SetLastError = true)] + public static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo); + + [DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)] + public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect); + + public static List> GetMemoryAddresses(this Process process) { - uint handle = process.CorProcess.GetHandle(); - - var proc = System.Diagnostics.Process.GetProcessById((int)process.Id); - baseAddress = proc.MainModule.BaseAddress.ToInt64(); - long addr = baseAddress; + var result = new List>(); + SYSTEM_INFO sysinfo = new SYSTEM_INFO(); + GetSystemInfo(out sysinfo); - byte[] memory = null; + uint handle = process.CorProcess.GetHandle(); + long address = 0; + MEMORY_BASIC_INFORMATION m = new MEMORY_BASIC_INFORMATION(); - while (true) + while (address < sysinfo.lpMaximumApplicationAddress.ToInt64()) { - byte[] temp = new byte[1024]; - int outSize; - bool success = ReadProcessMemory(new IntPtr(handle), new IntPtr(addr), temp, temp.Length, out outSize); - - addr += 1024; - - if (outSize == 0) + if (!VirtualQueryEx(new IntPtr(handle), new IntPtr(address), out m, (uint)Marshal.SizeOf(m))) break; - if (memory == null) { - memory = new byte[outSize]; - Array.Copy(temp, memory, outSize); - } else { - // expand memory - byte[] newTemp = new byte[memory.Length]; - Array.Copy(memory, newTemp, memory.Length); - - memory = new byte[memory.Length + outSize]; - Array.Copy(newTemp, memory, newTemp.Length); - Array.Copy(temp, 0, memory, newTemp.Length, outSize); + try { + byte[] temp = new byte[m.RegionSize.ToInt64()]; + int outSize; + if (!ReadProcessMemory(new IntPtr(handle), new IntPtr(address), temp, temp.Length, out outSize)) + continue; + } catch { + continue; + } finally { + // next address + address = m.BaseAddress.ToInt64() + m.RegionSize.ToInt64(); } - if (!success) // break when we cannot read anymore - break; + result.Add(new Tuple(m.BaseAddress.ToInt64(), m.RegionSize.ToInt64())); + } + + return result; + } + + public static byte[] ReadProcessMemory(this Process process, long startAddress, long size) + { + uint handle = process.CorProcess.GetHandle(); + + byte[] temp = new byte[size]; + int outSize; + bool success = ReadProcessMemory(new IntPtr(handle), new IntPtr(startAddress), temp, temp.Length, out outSize); + + if (!success || outSize == 0) { + var proc = System.Diagnostics.Process.GetProcessById((int)process.Id); + return process.ReadProcessMemory(proc.MainModule.BaseAddress.ToInt64(), (long)4096); } - return memory; + return temp; } } } diff --git a/src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs b/src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs index a1e0e5208a..97b4ba5b48 100755 --- a/src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs @@ -294,7 +294,6 @@ namespace ICSharpCode.SharpDevelop.Gui this.Children.Add(editor); editor.TextArea.ReadOnlySectionProvider = readOnlyRegion = new BeginReadOnlySectionProvider(); - editor.TextArea.TextEntered += new TextCompositionEventHandler(editor_TextArea_TextEntered); editor.TextArea.PreviewKeyDown += new KeyEventHandler(editor_TextArea_PreviewKeyDown); } diff --git a/src/Main/StartUp/Project/Resources/BitmapResources.resources b/src/Main/StartUp/Project/Resources/BitmapResources.resources index 929a830270..be36c125ea 100644 Binary files a/src/Main/StartUp/Project/Resources/BitmapResources.resources and b/src/Main/StartUp/Project/Resources/BitmapResources.resources differ