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<
<value>Jump to address:</value> <value>Jump to address:</value>
</data> </data>
<data name="MainWindow.Windows.Debug.MemoryPad.Refresh" xml:space="preserve"> <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>
<data name="MainWindow.Windows.Debug.ParallelStack" xml:space="preserve"> <data name="MainWindow.Windows.Debug.ParallelStack" xml:space="preserve">
<value>Parallel Stacks</value> <value>Parallel Stacks</value>

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

@ -47,7 +47,9 @@ OutputPad.Toolbar.ClearOutputWindow = OutputPadIcons\ClearOutputWindow.png
OutputPad.Toolbar.ToggleWordWrap = OutputPadIcons\ToggleWordWrap.png OutputPad.Toolbar.ToggleWordWrap = OutputPadIcons\ToggleWordWrap.png
#Memory pad #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.OpenFolderBitmap = ProjectBrowserIcons\Folder.Open.png
Icons.16x16.ClosedFolderBitmap = ProjectBrowserIcons\Folder.Closed.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 @@
</Path> </Path>
<Path name="/SharpDevelop/Pads/MemoryPad/ToolBar"> <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="PreviousAddressLabel"
<ToolbarItem id="JumpToAddressCombo" type="ComboBox" class="ICSharpCode.SharpDevelop.Gui.Pads.JumpToAddressCommand"/> type="Item"
<ToolbarItem id="Separator1" type="Separator"/> 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" <ToolbarItem id="RefreshMemory"
type="Item" type="Item"
icon="Icons.16x16.Refresh" icon="Icons.16x16.Refresh"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.Refresh}" tooltip="${res:MainWindow.Windows.Debug.MemoryPad.Refresh}"
class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshMemoryCommand"/> class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshAddressCommand"/>
</Path> </Path>
<Path name="/SharpDevelop/Services/DebuggerService/Visualizers"> <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
} }
} }
public sealed class RefreshMemoryCommand : AbstractCommand public abstract class ItemMemoryCommand : AbstractCommand
{ {
MemoryPad pad; protected MemoryPad pad;
protected override void OnOwnerChanged(EventArgs e) protected override void OnOwnerChanged(EventArgs e)
{ {
@ -52,13 +52,38 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
base.OnOwnerChanged(e); 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() public override void Run()
{ {
if (this.pad == null) if (this.pad == null)
return; 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
{ {
public sealed class MemoryPad : DebuggerPad public sealed class MemoryPad : DebuggerPad
{ {
Dictionary<long, int> addressesMapping = new Dictionary<long, int>(); int currentAddressIndex;
ConsoleControl console; ConsoleControl console;
int addressStep = 16; int addressStep = 16;
Process debuggedProcess; Process debuggedProcess;
List<Tuple<long, long>> memoryAddresses = new List<Tuple<long, long>>();
Dictionary<long, int> addressesMapping = new Dictionary<long, int>();
public MemoryPad() public MemoryPad()
{ {
@ -40,13 +42,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
protected override void SelectProcess(Process process) protected override void SelectProcess(Process process)
{ {
if (debuggedProcess != null) { if (process == null)
debuggedProcess.Paused -= OnProcessPaused; return;
}
debuggedProcess = process; debuggedProcess = process;
if (debuggedProcess != null) { memoryAddresses = debuggedProcess.GetMemoryAddresses();
debuggedProcess.Paused += OnProcessPaused; currentAddressIndex = 0;
}
} }
public override void RefreshPad() public override void RefreshPad()
@ -62,16 +63,33 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
address = address.Substring(2); address = address.Substring(2);
long addr = Int64.Parse(address, NumberStyles.AllowHexSpecifier); 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; int line;
if (addressesMapping.ContainsKey(addr - mod)) if (addressesMapping.ContainsKey(addr - mod))
line = addressesMapping[addr - mod]; line = addressesMapping[addr - mod];
else else
line = 1; line = 1;
// jump
console.SelectText(line, 0, 8); console.SelectText(line, 0, 8);
console.JumpToLine(line); console.JumpToLine(line);
} catch (System.Exception ex) { } catch (System.Exception ex) {
#if DEBUG #if DEBUG
LoggingService.Error(ex.Message); 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) if (debuggedProcess == null || debugger.IsProcessRunning)
return; return;
if (!force && addressesMapping.Count > 0) if (memoryAddresses.Count == 0)
return; return;
if (force) { console.Clear();addressesMapping.Clear();
addressesMapping.Clear();
console.Clear();
}
long address; // get current address
byte[] memory = debuggedProcess.ReadProcessMemory(out address); var item = memoryAddresses[currentAddressIndex];
long address = item.Item1;
long size = item.Item2;
if (memory == null) byte[] memory = debuggedProcess.ReadProcessMemory(address, size);
return; System.Diagnostics.Debug.Assert(memory != null);
int index = 0;
int div = memory.Length / addressStep; int div = memory.Length / addressStep;
int mod = memory.Length % addressStep; int mod = memory.Length % addressStep;
int index = 0;
while (index < div) { while (index < div) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
addressesMapping.Add(address, index + 1); addressesMapping.Add(address, index + 1);
// write address // write address
sb.Append(address.ToString("X8"));address += addressStep; sb.Append(address.ToString("X8")); address += (long)addressStep;
sb.Append(" "); sb.Append(" ");
// write bytes // write bytes
@ -121,13 +138,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
string s = sb1.ToString(); string s = sb1.ToString();
s = Regex.Replace(s, @"\r\n", string.Empty); s = Regex.Replace(s, @"\r\n", string.Empty);
s = Regex.Replace(s, @"\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(s);
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
// start writing in console // start writing in console
console.Append(sb.ToString()); console.Append(sb.ToString());
index++; index++;
} }
@ -151,7 +167,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
string s = sb1.ToString(); string s = sb1.ToString();
s = Regex.Replace(s, @"\r\n", string.Empty); s = Regex.Replace(s, @"\r\n", string.Empty);
s = Regex.Replace(s, @"\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(s);
sb.Append(Environment.NewLine); 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(); 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 @@
#pragma warning disable 1591 #pragma warning disable 1591
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -38,6 +39,62 @@ namespace Debugger.Interop
Synchronize = 0x00100000 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 public static class NativeMethods
{ {
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
@ -63,7 +120,7 @@ namespace Debugger.Interop
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, 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)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory( public static extern bool ReadProcessMemory(
@ -74,45 +131,59 @@ namespace Debugger.Interop
out int lpNumberOfBytesRead 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 result = new List<Tuple<long, long>>();
SYSTEM_INFO sysinfo = new SYSTEM_INFO();
var proc = System.Diagnostics.Process.GetProcessById((int)process.Id); GetSystemInfo(out sysinfo);
baseAddress = proc.MainModule.BaseAddress.ToInt64();
long addr = baseAddress;
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]; if (!VirtualQueryEx(new IntPtr(handle), new IntPtr(address), out m, (uint)Marshal.SizeOf(m)))
int outSize;
bool success = ReadProcessMemory(new IntPtr(handle), new IntPtr(addr), temp, temp.Length, out outSize);
addr += 1024;
if (outSize == 0)
break; break;
if (memory == null) { try {
memory = new byte[outSize]; byte[] temp = new byte[m.RegionSize.ToInt64()];
Array.Copy(temp, memory, outSize); int outSize;
} else { if (!ReadProcessMemory(new IntPtr(handle), new IntPtr(address), temp, temp.Length, out outSize))
// expand memory continue;
byte[] newTemp = new byte[memory.Length]; } catch {
Array.Copy(memory, newTemp, memory.Length); continue;
} finally {
memory = new byte[memory.Length + outSize]; // next address
Array.Copy(newTemp, memory, newTemp.Length); address = m.BaseAddress.ToInt64() + m.RegionSize.ToInt64();
Array.Copy(temp, 0, memory, newTemp.Length, outSize);
} }
if (!success) // break when we cannot read anymore result.Add(new Tuple<long, long>(m.BaseAddress.ToInt64(), m.RegionSize.ToInt64()));
break; }
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
this.Children.Add(editor); this.Children.Add(editor);
editor.TextArea.ReadOnlySectionProvider = readOnlyRegion = new BeginReadOnlySectionProvider(); editor.TextArea.ReadOnlySectionProvider = readOnlyRegion = new BeginReadOnlySectionProvider();
editor.TextArea.TextEntered += new TextCompositionEventHandler(editor_TextArea_TextEntered); editor.TextArea.TextEntered += new TextCompositionEventHandler(editor_TextArea_TextEntered);
editor.TextArea.PreviewKeyDown += new KeyEventHandler(editor_TextArea_PreviewKeyDown); editor.TextArea.PreviewKeyDown += new KeyEventHandler(editor_TextArea_PreviewKeyDown);
} }

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

Binary file not shown.
Loading…
Cancel
Save