Sharing memory.

This commit is contained in:
Ben Vanik
2015-05-24 00:02:47 -07:00
parent 576d6492dc
commit da655d15b3
12 changed files with 373 additions and 18 deletions

View File

@@ -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);
}

View File

@@ -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
}
}

View File

@@ -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;

View 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);
}
}
}

View 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);
}
}

View File

@@ -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" />