Browse Source

Add memory pad for debugged process memory

pull/21/head
Eusebiu Marcu 15 years ago
parent
commit
70ee998c95
  1. 9
      data/resources/StringResources.resx
  2. 2
      data/resources/image/BitmapResources/BitmapResources.res
  3. BIN
      data/resources/image/BitmapResources/PadIcons/memory.png
  4. 18
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  5. 2
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  6. 64
      src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/MemoryPadCommands.cs
  7. 169
      src/AddIns/Debugger/Debugger.AddIn/Pads/MemoryPad.cs
  8. 94
      src/AddIns/Debugger/Debugger.Core/Interop/NativeMethods.cs
  9. 4
      src/AddIns/Debugger/Debugger.Core/Process.cs
  10. 31
      src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs
  11. BIN
      src/Main/StartUp/Project/Resources/BitmapResources.resources

9
data/resources/StringResources.resx

@ -5728,6 +5728,15 @@ Microsoft.Tools.WindowsInstallerXml.Extensions.NetFxCompiler, WixNetFxExtension< @@ -5728,6 +5728,15 @@ Microsoft.Tools.WindowsInstallerXml.Extensions.NetFxCompiler, WixNetFxExtension<
<data name="MainWindow.Windows.Debug.ObjectGraph" xml:space="preserve">
<value>Object Graph</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad" xml:space="preserve">
<value>Memory</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.JumpTo" xml:space="preserve">
<value>Jump to address:</value>
</data>
<data name="MainWindow.Windows.Debug.MemoryPad.Refresh" xml:space="preserve">
<value>Refresh</value>
</data>
<data name="MainWindow.Windows.Debug.ParallelStack" xml:space="preserve">
<value>Parallel Stacks</value>
</data>

2
data/resources/image/BitmapResources/BitmapResources.res

@ -46,6 +46,8 @@ ParallelStacks.ZoomControl = PadIcons\ZoomControl.png @@ -46,6 +46,8 @@ ParallelStacks.ZoomControl = PadIcons\ZoomControl.png
OutputPad.Toolbar.ClearOutputWindow = OutputPadIcons\ClearOutputWindow.png
OutputPad.Toolbar.ToggleWordWrap = OutputPadIcons\ToggleWordWrap.png
#Memory pad
MemoryPad.Icon = PadIcons\memory.png
Icons.16x16.OpenFolderBitmap = ProjectBrowserIcons\Folder.Open.png
Icons.16x16.ClosedFolderBitmap = ProjectBrowserIcons\Folder.Closed.png

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

18
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -117,6 +117,13 @@ @@ -117,6 +117,13 @@
class = "ICSharpCode.SharpDevelop.Gui.Pads.ConsolePad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "MemoryPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.MemoryPad}"
icon = "MemoryPad.Icon"
class = "ICSharpCode.SharpDevelop.Gui.Pads.MemoryPad"
defaultPosition = "Bottom, Hidden" />
<Pad id = "WatchPad"
category = "Debugger"
title = "${res:MainWindow.Windows.Debug.Watch}"
@ -191,6 +198,17 @@ @@ -191,6 +198,17 @@
/>
</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="RefreshMemory"
type="Item"
icon="Icons.16x16.Refresh"
tooltip="${res:MainWindow.Windows.Debug.MemoryPad.Refresh}"
class="ICSharpCode.SharpDevelop.Gui.Pads.RefreshMemoryCommand"/>
</Path>
<Path name="/SharpDevelop/Services/DebuggerService/Visualizers">
<Class class="Debugger.AddIn.Visualizers.TextVisualizerDescriptor" />
<Class class="Debugger.AddIn.Visualizers.XmlVisualizerDescriptor" />

2
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -102,6 +102,7 @@ @@ -102,6 +102,7 @@
<DependentUpon>CallStackPad.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Pads\Commands\MemoryPadCommands.cs" />
<Compile Include="Pads\Commands\ParallelStacksViewCommands.cs" />
<Compile Include="Pads\Commands\SelectLanguageCommand.cs" />
<Compile Include="Pads\Commands\WatchPadCommands.cs" />
@ -120,6 +121,7 @@ @@ -120,6 +121,7 @@
<Compile Include="Pads\Controls\WatchListAutoCompleteCell.cs">
<DependentUpon>WatchListAutoCompleteCell.xaml</DependentUpon>
</Compile>
<Compile Include="Pads\MemoryPad.cs" />
<Compile Include="Pads\ParallelPad\DrawSurface.xaml.cs">
<DependentUpon>DrawSurface.xaml</DependentUpon>
<SubType>Code</SubType>

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

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public sealed class JumpToAddressCommand : AbstractComboBoxCommand
{
MemoryPad pad;
ComboBox comboBox;
protected override void OnOwnerChanged(EventArgs e)
{
this.pad = this.Owner as MemoryPad;
if (this.pad == null)
return;
comboBox = this.ComboBox as ComboBox;
if (this.comboBox == null)
return;
comboBox.KeyUp += (s, ea) => { if (ea.Key == Key.Enter) Run(); };
comboBox.IsEditable = true;
comboBox.Width = 130;
base.OnOwnerChanged(e);
}
public override void Run()
{
if (this.pad != null && this.comboBox != null) {
pad.JumpToAddress(comboBox.Text);
}
base.Run();
}
}
public sealed class RefreshMemoryCommand : AbstractCommand
{
MemoryPad pad;
protected override void OnOwnerChanged(EventArgs e)
{
this.pad = this.Owner as MemoryPad;
if (this.pad == null)
return;
base.OnOwnerChanged(e);
}
public override void Run()
{
if (this.pad == null)
return;
this.pad.Refresh(true);
}
}
}

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

@ -0,0 +1,169 @@ @@ -0,0 +1,169 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using Debugger;
using Debugger.Interop;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Debugging;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public sealed class MemoryPad : DebuggerPad
{
Dictionary<long, int> addressesMapping = new Dictionary<long, int>();
ConsoleControl console;
int addressStep = 16;
Process debuggedProcess;
public MemoryPad()
{
this.console = new ConsoleControl();
this.panel.Children.Add(console);
this.console.Encoding = Encoding.Default;
RefreshPad();
this.console.SetReadonly();
}
protected override ToolBar BuildToolBar()
{
return ToolBarService.CreateToolBar(panel, this, "/SharpDevelop/Pads/MemoryPad/ToolBar");
}
protected override void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= OnProcessPaused;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += OnProcessPaused;
}
}
public override void RefreshPad()
{
Refresh();
base.RefreshPad();
}
public void JumpToAddress(string address)
{
try {
if (address.StartsWith("0x"))
address = address.Substring(2);
long addr = Int64.Parse(address, NumberStyles.AllowHexSpecifier);
long mod = addr % addressStep;
int line;
if (addressesMapping.ContainsKey(addr - mod))
line = addressesMapping[addr - mod];
else
line = 1;
console.SelectText(line, 0, 8);
console.JumpToLine(line);
} catch (System.Exception ex) {
#if DEBUG
LoggingService.Error(ex.Message);
#endif
}
}
public void Refresh(bool force = false)
{
if (debuggedProcess == null || debugger.IsProcessRunning)
return;
if (!force && addressesMapping.Count > 0)
return;
if (force) {
addressesMapping.Clear();
console.Clear();
}
long address;
byte[] memory = debuggedProcess.ReadProcessMemory(out address);
if (memory == null)
return;
int index = 0;
int div = memory.Length / addressStep;
int mod = memory.Length % addressStep;
while (index < div) {
StringBuilder sb = new StringBuilder();
addressesMapping.Add(address, index + 1);
// write address
sb.Append(address.ToString("X8"));address += addressStep;
sb.Append(" ");
// write bytes
for (int i = 0; i < addressStep; ++i) {
sb.Append(memory[index * addressStep + i].ToString("X2") + " ");
}
// write chars
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < addressStep; ++i) {
sb1.Append(((char)memory[index * addressStep + i]).ToString());
}
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);
sb.Append(s);
sb.Append(Environment.NewLine);
// start writing in console
console.Append(sb.ToString());
index++;
}
if (mod != 0) {
// write the rest of memory
StringBuilder sb = new StringBuilder();
addressesMapping.Add(address, index + 1);
// write address
sb.Append(address.ToString("X8"));
sb.Append(" ");
// write bytes
for (int i = 0; i < mod; ++i) {
sb.Append(memory[index * addressStep + i].ToString("X2") + " ");
}
// write chars
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < mod; ++i) {
sb1.Append(((char)memory[index * addressStep + i]).ToString());
}
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);
sb.Append(s);
sb.Append(Environment.NewLine);
// start writing in console
console.Append(sb.ToString());
}
}
private void OnProcessPaused(object sender, ProcessEventArgs e)
{
Refresh();
}
}
}

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

@ -7,8 +7,37 @@ using System; @@ -7,8 +7,37 @@ using System;
using System.Runtime.InteropServices;
using System.Text;
using Debugger.Interop.CorDebug;
namespace Debugger.Interop
{
{
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public IntPtr RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
public static class NativeMethods
{
[DllImport("kernel32.dll")]
@ -22,6 +51,69 @@ namespace Debugger.Interop @@ -22,6 +51,69 @@ namespace Debugger.Interop
[DllImport("mscoree.dll", CharSet=CharSet.Unicode)]
public static extern int GetRequestedRuntimeVersion(string exeFilename, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pVersion, Int32 cchBuffer, out Int32 dwLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool VirtualQueryEx(IntPtr hProcess,
IntPtr lpAddress,
out MEMORY_BASIC_INFORMATION lpBuffer,
uint dwLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
out int lpNumberOfBytesRead
);
public static byte[] ReadProcessMemory(this Process process, out long baseAddress)
{
uint handle = process.CorProcess.GetHandle();
var proc = System.Diagnostics.Process.GetProcessById((int)process.Id);
baseAddress = proc.MainModule.BaseAddress.ToInt64();
long addr = baseAddress;
byte[] memory = null;
while (true)
{
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)
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);
}
if (!success) // break when we cannot read anymore
break;
}
return memory;
}
}
}

4
src/AddIns/Debugger/Debugger.Core/Process.cs

@ -362,6 +362,10 @@ namespace Debugger @@ -362,6 +362,10 @@ namespace Debugger
get { return pauseSession == null; }
}
public uint Id {
get { return corProcess.GetID(); }
}
public bool IsPaused {
get { return !IsRunning; }
}

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

@ -1,19 +1,21 @@ @@ -1,19 +1,21 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using ICSharpCode.AvalonEdit;
using ICSharpCode.Core.Presentation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
using ICSharpCode.Core.Presentation;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.AvalonEdit;
@ -303,6 +305,21 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -303,6 +305,21 @@ namespace ICSharpCode.SharpDevelop.Gui
}
}
public Encoding Encoding {
get {
return this.editor.Encoding;
}
set {
this.editor.Encoding = value;
}
}
public void SelectText(int line, int column, int length)
{
int offset = this.editor.Document.GetOffset(new TextLocation(line, column));
this.editor.Select(offset, length);
}
public void SetHighlighting(string language)
{
editor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition(language);
@ -338,6 +355,11 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -338,6 +355,11 @@ namespace ICSharpCode.SharpDevelop.Gui
this.editor.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
}
public void JumpToLine(int line)
{
this.editor.ScrollToLine(line);
}
public int CommandOffset {
get { return readOnlyRegion.EndOffset; }
}
@ -369,6 +391,11 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -369,6 +391,11 @@ namespace ICSharpCode.SharpDevelop.Gui
if (handler != null)
handler(this, e);
}
public void Clear()
{
editor.Clear();
}
}
public class BeginReadOnlySectionProvider : IReadOnlySectionProvider

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

Binary file not shown.
Loading…
Cancel
Save