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