Browse Source

Read virtual memory of a process.

pull/21/head
Eusebiu Marcu 15 years ago
parent
commit
6fe1ac9d76
  1. 11
      data/resources/StringResources.resx
  2. 4
      data/resources/image/BitmapResources/BitmapResources.res
  3. BIN
      data/resources/image/BitmapResources/PadIcons/NextMemory.png
  4. BIN
      data/resources/image/BitmapResources/PadIcons/PreviousMemory.png
  5. 26
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  6. 33
      src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs
  7. 103
      src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs
  8. 131
      src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs
  9. 1
      src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs
  10. BIN
      src/Main/StartUp/Project/Resources/BitmapResources.resources

11
data/resources/StringResources.resx

@ -5735,7 +5735,16 @@ Microsoft.Tools.WindowsInstallerXml.Extensions.NetFxCompiler, WixNetFxExtension< @@ -5735,7 +5735,16 @@ Microsoft.Tools.WindowsInstallerXml.Extensions.NetFxCompiler, WixNetFxExtension<
<value>Jump to address:</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.Refresh" xml:space="preserve">
<value>Refresh</value>
<value>Refresh current addresses</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.NextAddress" xml:space="preserve">
<value>Next virtual addresses</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.AddressNotFound" xml:space="preserve">
<value>The address {0} was not found!</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.PreviousAddress" xml:space="preserve">
<value>Previous virtual addresses</value>
</data>
<data name="MainWindow.Windows.Debug.ParallelStack" xml:space="preserve">
<value>Parallel Stacks</value>

4
data/resources/image/BitmapResources/BitmapResources.res

@ -47,7 +47,9 @@ OutputPad.Toolbar.ClearOutputWindow = OutputPadIcons\ClearOutputWindow.png @@ -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

BIN
data/resources/image/BitmapResources/PadIcons/NextMemory.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
data/resources/image/BitmapResources/PadIcons/PreviousMemory.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

26
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -199,14 +199,32 @@ @@ -199,14 +199,32 @@
</Path>
<Path name="/SharpDevelop/Pads/MemoryPad/ToolBar">
<ToolbarItem id="JumpToAddressLabel" type="Item" label="${res:MainWindow.Windows.Debug.MemoryPad.JumpTo}" class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="JumpToAddressCombo" type="ComboBox" class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="Separator1" type="Separator"/>
<ToolbarItem id="PreviousAddressLabel"
type="Item"
icon="MemoryPad.PreviousMemoryIcon"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.PreviousAddress}"
class="ICSharpCode.SharpDevelop.Gui.Pads.PreviousAddressCommand"/>
<ToolbarItem id="NextAddressLabel"
type="Item"
icon="MemoryPad.NextMemoryIcon"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.NextAddress}"
class="ICSharpCode.SharpDevelop.Gui.Pads.NextAddressCommand"/>
<ToolbarItem id="Separator1"
type="Separator"/>
<ToolbarItem id="JumpToAddressLabel"
type="Item"
label="${res:MainWindow.Windows.Debug.MemoryPad.JumpTo}"
class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="JumpToAddressCombo"
type="ComboBox"
class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/>
<ToolbarItem id="Separator2"
type="Separator"/>
<ToolbarItem id="RefreshMemory"
type="Item"
icon="Icons.16x16.Refresh"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.Refresh}"
class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshMemoryCommand"/>
class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshAddressCommand"/>
</Path>
<Path name="/SharpDevelop/Services/DebuggerService/Visualizers">

33
src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs

@ -40,9 +40,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -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 @@ -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();
}
}
}

103
src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs

@ -18,11 +18,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -18,11 +18,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public sealed class MemoryPad : DebuggerPad
{
Dictionary<long, int> addressesMapping = new Dictionary<long, int>();
int currentAddressIndex;
ConsoleControl console;
int addressStep = 16;
Process debuggedProcess;
List<Tuple<long, long>> memoryAddresses = new List<Tuple<long, long>>();
Dictionary<long, int> addressesMapping = new Dictionary<long, int>();
public MemoryPad()
{
@ -40,13 +42,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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<Tuple<long, long>> 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;
}
}
}

131
src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs

@ -4,6 +4,7 @@ @@ -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 @@ -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 @@ -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 @@ -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<Tuple<long, long>> 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<Tuple<long, long>>();
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<long, long>(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;
}
}
}

1
src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs

@ -294,7 +294,6 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -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);
}

BIN
src/Main/StartUp/Project/Resources/BitmapResources.resources

Binary file not shown.
Loading…
Cancel
Save