Sharing memory.
This commit is contained in:
@@ -12,7 +12,6 @@ using xe.debug.proto;
|
||||
using Xenia.Debug.Utilities;
|
||||
|
||||
namespace Xenia.Debug {
|
||||
|
||||
public class Debugger {
|
||||
private readonly static string kServerHostname = "";
|
||||
private readonly static int kServerPort = 19000;
|
||||
@@ -35,6 +34,19 @@ namespace Xenia.Debug {
|
||||
pendingRequests = new ConcurrentDictionary<uint, PendingRequest>();
|
||||
private uint nextRequestId = 1;
|
||||
|
||||
private FileMappingHandle memoryHandle;
|
||||
public IntPtr Membase {
|
||||
get;
|
||||
}
|
||||
|
||||
public unsafe byte* TranslateVirtual(uint address) {
|
||||
return (byte*)Membase.ToPointer() + address;
|
||||
}
|
||||
|
||||
public unsafe byte* TranslatePhysical(uint address) {
|
||||
return (byte*)Membase.ToPointer() + 0xFFFFFFFF + address;
|
||||
}
|
||||
|
||||
public event EventHandler<State> StateChanged;
|
||||
|
||||
public State CurrentState {
|
||||
@@ -126,6 +138,27 @@ namespace Xenia.Debug {
|
||||
int requestDataOffset = AttachRequest.EndAttachRequest(fbb);
|
||||
var response = await CommitRequest(fbb, RequestData.AttachRequest, requestDataOffset);
|
||||
|
||||
System.Diagnostics.Debug.Assert(response.ResponseDataType ==
|
||||
ResponseData.AttachResponse);
|
||||
var attachResponse = new AttachResponse();
|
||||
response.GetResponseData(attachResponse);
|
||||
|
||||
// Open mmap to share memroy.
|
||||
memoryHandle = FileMapping.OpenFileMapping(
|
||||
FileMapAccess.FILE_MAP_ALL_ACCESS, false, attachResponse.MemoryFile);
|
||||
if (memoryHandle.IsInvalid) {
|
||||
System.Diagnostics.Debug.Fail("Unable to open target memory");
|
||||
Detach();
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the memory system. This maps the emulator memory into our address
|
||||
// space.
|
||||
if (!Memory.InitializeMapping(memoryHandle)) {
|
||||
Detach();
|
||||
return;
|
||||
}
|
||||
|
||||
OnStateChanged(State.Attached);
|
||||
}
|
||||
|
||||
@@ -134,8 +167,17 @@ namespace Xenia.Debug {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.Close();
|
||||
socket = null;
|
||||
Memory.UninitializeMapping();
|
||||
|
||||
if (memoryHandle != null) {
|
||||
memoryHandle.Close();
|
||||
memoryHandle = null;
|
||||
}
|
||||
|
||||
if (socket != null) {
|
||||
socket.Close();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
OnStateChanged(State.Detached);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,100 @@ using System.Threading.Tasks;
|
||||
using Xenia.Debug.Utilities;
|
||||
|
||||
namespace Xenia.Debug {
|
||||
public class Memory : Changeable {
|
||||
public class Memory : Changeable, IDisposable {
|
||||
private readonly Debugger debugger;
|
||||
|
||||
private class MapInfo {
|
||||
public ulong virtualAddressStart;
|
||||
public ulong virtualAddressEnd;
|
||||
public ulong targetAddress;
|
||||
public IntPtr ptr;
|
||||
}
|
||||
private MapInfo[] mapInfos = new MapInfo[]{
|
||||
// From memory.cc:
|
||||
new MapInfo(){virtualAddressStart = 0x00000000, virtualAddressEnd = 0x3FFFFFFF,
|
||||
targetAddress = 0x0000000000000000},
|
||||
new MapInfo(){virtualAddressStart = 0x40000000, virtualAddressEnd = 0x7EFFFFFF,
|
||||
targetAddress = 0x0000000040000000},
|
||||
new MapInfo(){virtualAddressStart = 0x7F000000, virtualAddressEnd = 0x7FFFFFFF,
|
||||
targetAddress = 0x0000000100000000},
|
||||
new MapInfo(){virtualAddressStart = 0x80000000, virtualAddressEnd = 0x8FFFFFFF,
|
||||
targetAddress = 0x0000000080000000},
|
||||
new MapInfo(){virtualAddressStart = 0x90000000, virtualAddressEnd = 0x9FFFFFFF,
|
||||
targetAddress = 0x0000000080000000},
|
||||
new MapInfo(){virtualAddressStart = 0xA0000000, virtualAddressEnd = 0xBFFFFFFF,
|
||||
targetAddress = 0x0000000100000000},
|
||||
new MapInfo(){virtualAddressStart = 0xC0000000, virtualAddressEnd = 0xDFFFFFFF,
|
||||
targetAddress = 0x0000000100000000},
|
||||
new MapInfo(){virtualAddressStart = 0xE0000000, virtualAddressEnd = 0xFFFFFFFF,
|
||||
targetAddress = 0x0000000100000000},
|
||||
new MapInfo(){virtualAddressStart = 0x100000000, virtualAddressEnd = 0x11FFFFFFF,
|
||||
targetAddress = 0x0000000100000000},
|
||||
};
|
||||
|
||||
public UIntPtr VirtualMembase;
|
||||
public UIntPtr PhysicalMembase;
|
||||
|
||||
public Memory(Debugger debugger) {
|
||||
this.debugger = debugger;
|
||||
}
|
||||
|
||||
public bool InitializeMapping(FileMappingHandle mappingHandle) {
|
||||
ulong mappingBase = 0x100000000;
|
||||
foreach (MapInfo mapInfo in mapInfos) {
|
||||
uint targetAddressLow = (uint)mapInfo.targetAddress;
|
||||
uint targetAddressHigh = (uint)(mapInfo.targetAddress >> 32);
|
||||
mapInfo.ptr = FileMapping.MapViewOfFileEx(
|
||||
mappingHandle, FileMapAccess.FILE_MAP_ALL_ACCESS,
|
||||
targetAddressHigh, targetAddressLow,
|
||||
mapInfo.virtualAddressEnd - mapInfo.virtualAddressStart + 1,
|
||||
mappingBase + mapInfo.virtualAddressStart);
|
||||
if (mapInfo.ptr == IntPtr.Zero) {
|
||||
System.Diagnostics.Debug.Fail("Unable to place memory at target address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VirtualMembase = new UIntPtr(mappingBase);
|
||||
PhysicalMembase = new UIntPtr(mappingBase + 0x100000000);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UninitializeMapping() {
|
||||
foreach (MapInfo mapInfo in mapInfos) {
|
||||
FileMapping.UnmapViewOfFile(mapInfo.ptr);
|
||||
mapInfo.ptr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDispose() {
|
||||
UninitializeMapping();
|
||||
}
|
||||
|
||||
public MemoryView CreateView() {
|
||||
return new MemoryView(this);
|
||||
}
|
||||
|
||||
#region Dispose
|
||||
private bool disposed = false;
|
||||
|
||||
~Memory() {
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (!disposed) {
|
||||
if (disposing) {
|
||||
// TODO: dispose managed state (managed objects).
|
||||
}
|
||||
OnDispose();
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,25 @@ public sealed class AttachResponse : Table {
|
||||
public static AttachResponse GetRootAsAttachResponse(ByteBuffer _bb, AttachResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
|
||||
public AttachResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
|
||||
|
||||
public string MemoryFile { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } }
|
||||
public string FunctionsFile { get { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; } }
|
||||
public string FunctionsTraceFile { get { int o = __offset(8); return o != 0 ? __string(o + bb_pos) : null; } }
|
||||
|
||||
public static void StartAttachResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
|
||||
public static int CreateAttachResponse(FlatBufferBuilder builder,
|
||||
int memory_file = 0,
|
||||
int functions_file = 0,
|
||||
int functions_trace_file = 0) {
|
||||
builder.StartObject(3);
|
||||
AttachResponse.AddFunctionsTraceFile(builder, functions_trace_file);
|
||||
AttachResponse.AddFunctionsFile(builder, functions_file);
|
||||
AttachResponse.AddMemoryFile(builder, memory_file);
|
||||
return AttachResponse.EndAttachResponse(builder);
|
||||
}
|
||||
|
||||
public static void StartAttachResponse(FlatBufferBuilder builder) { builder.StartObject(3); }
|
||||
public static void AddMemoryFile(FlatBufferBuilder builder, int memoryFileOffset) { builder.AddOffset(0, memoryFileOffset, 0); }
|
||||
public static void AddFunctionsFile(FlatBufferBuilder builder, int functionsFileOffset) { builder.AddOffset(1, functionsFileOffset, 0); }
|
||||
public static void AddFunctionsTraceFile(FlatBufferBuilder builder, int functionsTraceFileOffset) { builder.AddOffset(2, functionsTraceFileOffset, 0); }
|
||||
public static int EndAttachResponse(FlatBufferBuilder builder) {
|
||||
int o = builder.EndObject();
|
||||
return o;
|
||||
|
||||
33
src/Xenia.Debug/Utilities/Disposable.cs
Normal file
33
src/Xenia.Debug/Utilities/Disposable.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Xenia.Debug.Utilities {
|
||||
public class Disposable : IDisposable {
|
||||
private bool disposed = false;
|
||||
|
||||
protected virtual void OnDispose() {
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (!disposed) {
|
||||
if (disposing) {
|
||||
// TODO: dispose managed state (managed objects).
|
||||
}
|
||||
OnDispose();
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
~Disposable() {
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/Xenia.Debug/Utilities/FileMapping.cs
Normal file
142
src/Xenia.Debug/Utilities/FileMapping.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Xenia.Debug.Utilities {
|
||||
// From: http://1code.codeplex.com/SourceControl/latest#Visual Studio 2008/CSFileMappingClient/Program.cs
|
||||
|
||||
/// <summary>
|
||||
/// Access rights for file mapping objects
|
||||
/// http://msdn.microsoft.com/en-us/library/aa366559.aspx
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FileMapAccess {
|
||||
FILE_MAP_COPY = 0x0001,
|
||||
FILE_MAP_WRITE = 0x0002,
|
||||
FILE_MAP_READ = 0x0004,
|
||||
FILE_MAP_ALL_ACCESS = 0x000F001F
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a wrapper class for a file mapping handle.
|
||||
/// </summary>
|
||||
[SuppressUnmanagedCodeSecurity,
|
||||
HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
|
||||
public sealed class FileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid {
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
private FileMappingHandle()
|
||||
: base(true) {
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
public FileMappingHandle(IntPtr handle, bool ownsHandle)
|
||||
: base(ownsHandle) {
|
||||
base.SetHandle(handle);
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success),
|
||||
DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
protected override bool ReleaseHandle() {
|
||||
return CloseHandle(base.handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The class exposes Windows APIs used in this code sample.
|
||||
/// </summary>
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
public class FileMapping {
|
||||
/// <summary>
|
||||
/// Opens a named file mapping object.
|
||||
/// </summary>
|
||||
/// <param name="dwDesiredAccess">
|
||||
/// The access to the file mapping object. This access is checked against
|
||||
/// any security descriptor on the target file mapping object.
|
||||
/// </param>
|
||||
/// <param name="bInheritHandle">
|
||||
/// If this parameter is TRUE, a process created by the CreateProcess
|
||||
/// function can inherit the handle; otherwise, the handle cannot be
|
||||
/// inherited.
|
||||
/// </param>
|
||||
/// <param name="lpName">
|
||||
/// The name of the file mapping object to be opened.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is an open handle to the
|
||||
/// specified file mapping object.
|
||||
/// </returns>
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern FileMappingHandle OpenFileMapping(
|
||||
FileMapAccess dwDesiredAccess, bool bInheritHandle, string lpName);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Maps a view of a file mapping into the address space of a calling
|
||||
/// process.
|
||||
/// </summary>
|
||||
/// <param name="hFileMappingObject">
|
||||
/// A handle to a file mapping object. The CreateFileMapping and
|
||||
/// OpenFileMapping functions return this handle.
|
||||
/// </param>
|
||||
/// <param name="dwDesiredAccess">
|
||||
/// The type of access to a file mapping object, which determines the
|
||||
/// protection of the pages.
|
||||
/// </param>
|
||||
/// <param name="dwFileOffsetHigh">
|
||||
/// A high-order DWORD of the file offset where the view begins.
|
||||
/// </param>
|
||||
/// <param name="dwFileOffsetLow">
|
||||
/// A low-order DWORD of the file offset where the view is to begin.
|
||||
/// </param>
|
||||
/// <param name="dwNumberOfBytesToMap">
|
||||
/// The number of bytes of a file mapping to map to the view. All bytes
|
||||
/// must be within the maximum size specified by CreateFileMapping.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is the starting address
|
||||
/// of the mapped view.
|
||||
/// </returns>
|
||||
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr MapViewOfFile(
|
||||
FileMappingHandle hFileMappingObject,
|
||||
FileMapAccess dwDesiredAccess,
|
||||
uint dwFileOffsetHigh,
|
||||
uint dwFileOffsetLow,
|
||||
ulong dwNumberOfBytesToMap);
|
||||
|
||||
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr MapViewOfFileEx(
|
||||
FileMappingHandle hFileMappingObject,
|
||||
FileMapAccess dwDesiredAccess,
|
||||
uint dwFileOffsetHigh,
|
||||
uint dwFileOffsetLow,
|
||||
ulong dwNumberOfBytesToMap,
|
||||
ulong lpBaseAddress);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Unmaps a mapped view of a file from the calling process's address
|
||||
/// space.
|
||||
/// </summary>
|
||||
/// <param name="lpBaseAddress">
|
||||
/// A pointer to the base address of the mapped view of a file that
|
||||
/// is to be unmapped.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\..\build\bin\Release\</OutputPath>
|
||||
@@ -31,6 +32,7 @@
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -88,6 +90,8 @@
|
||||
<Compile Include="ThreadList.cs" />
|
||||
<Compile Include="Utilities\Changeable.cs" />
|
||||
<Compile Include="Utilities\Dispatch.cs" />
|
||||
<Compile Include="Utilities\Disposable.cs" />
|
||||
<Compile Include="Utilities\FileMapping.cs" />
|
||||
<Compile Include="Utilities\TaskExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
Reference in New Issue
Block a user