Further support for identifying modules and threads
A slight restructure too
This commit is contained in:
parent
92d6635c4e
commit
ff54eb8b9e
|
@ -63,18 +63,24 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Debugger.cs" />
|
||||
<Compile Include="DebuggerEventListener.cs" />
|
||||
<Compile Include="DebuggerModule.cs" />
|
||||
<Compile Include="DebuggerProcess.cs" />
|
||||
<Compile Include="DebuggerCallstack.cs" />
|
||||
<Compile Include="DebuggerThread.cs" />
|
||||
<Compile Include="Debugger\Debugger.cs" />
|
||||
<Compile Include="Debugger\DebuggerEventListener.cs" />
|
||||
<Compile Include="Debugger\DebuggerInstance.cs" />
|
||||
<Compile Include="Debugger\DebuggerModule.cs" />
|
||||
<Compile Include="Debugger\DebuggerProcess.cs" />
|
||||
<Compile Include="Debugger\DebuggerCallstack.cs" />
|
||||
<Compile Include="DebuggerSymbols\DebuggerSymbolProvider.cs" />
|
||||
<Compile Include="Debugger\DebuggerSymbolServer.cs" />
|
||||
<Compile Include="Debugger\DebuggerThread.cs" />
|
||||
<Compile Include="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Form1.Designer.cs">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="DebuggerSymbols\HLECache\HLECacheFile.cs" />
|
||||
<Compile Include="DebuggerSymbols\HLECache\HLECacheProvider.cs" />
|
||||
<Compile Include="DebuggerSymbols\HLECache\Utils\INIReader.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ThreadHelpers.cs" />
|
||||
|
@ -91,7 +97,6 @@
|
|||
<Compile Include="Win32\Debugging\LOAD_DLL_DEBUG_INFO.cs" />
|
||||
<Compile Include="Win32\Debugging\NativeMethods.cs" />
|
||||
<Compile Include="Win32\Debugging\OUTPUT_DEBUG_STRING_INFO.cs" />
|
||||
<Compile Include="Win32\Debugging\PTHREAD_START_ROUTINE.cs" />
|
||||
<Compile Include="Win32\Debugging\RIP_INFO.cs" />
|
||||
<Compile Include="Win32\Debugging\UNLOAD_DLL_DEBUG_INFO.cs" />
|
||||
<Compile Include="Win32\Handles\NativeMethods.cs" />
|
||||
|
|
|
@ -7,11 +7,10 @@ using System.Text;
|
|||
using WinProcesses = VsChromium.Core.Win32.Processes;
|
||||
using WinDebug = VsChromium.Core.Win32.Debugging;
|
||||
using System.Runtime.InteropServices;
|
||||
using CxbxDebugger.TheadHelpers;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class Debugger : IDisposable
|
||||
public class Debugger : DebuggerEventListener, IDisposable
|
||||
{
|
||||
enum RunState
|
||||
{
|
||||
|
@ -32,28 +31,30 @@ namespace CxbxDebugger
|
|||
|
||||
RunState State = RunState.NotLaunched;
|
||||
|
||||
List<DebuggerModule> ModuleList = new List<DebuggerModule>();
|
||||
List<DebuggerThread> ThreadList = new List<DebuggerThread>();
|
||||
List<DebuggerProcess> ProcessList = new List<DebuggerProcess>();
|
||||
DebuggerInstance DebugInstance;
|
||||
|
||||
List<DebuggerEventListener> EventListeners = new List<DebuggerEventListener>();
|
||||
|
||||
CONTEXT_x86 lastReadCtxt = new CONTEXT_x86
|
||||
DebuggerSymbolServer SymbolSrv;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
ContextFlags =
|
||||
ContextFlags.CONTEXT_i386 |
|
||||
ContextFlags.CONTEXT_CONTROL |
|
||||
ContextFlags.CONTEXT_INTEGER |
|
||||
ContextFlags.CONTEXT_SEGMENTS
|
||||
};
|
||||
DebugInstance = null;
|
||||
|
||||
SymbolSrv = new DebuggerSymbolServer();
|
||||
|
||||
RegisterEventListener(this);
|
||||
}
|
||||
|
||||
public Debugger()
|
||||
{
|
||||
//
|
||||
Init();
|
||||
}
|
||||
|
||||
public Debugger(string[] x_args)
|
||||
{
|
||||
Init();
|
||||
|
||||
if (x_args == null)
|
||||
return;
|
||||
|
||||
|
@ -82,20 +83,17 @@ namespace CxbxDebugger
|
|||
|
||||
public void Break()
|
||||
{
|
||||
// This will ONLY suspend the main process
|
||||
// Not ideal if there are multiple processes in play
|
||||
|
||||
if (!hThread.IsInvalid)
|
||||
if (DebugInstance != null)
|
||||
{
|
||||
WinProcesses.NativeMethods.SuspendThread(hThread.DangerousGetHandle());
|
||||
DebugInstance.MainProcess.Suspend();
|
||||
}
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
if (!hThread.IsInvalid)
|
||||
if (DebugInstance != null)
|
||||
{
|
||||
WinProcesses.NativeMethods.ResumeThread(hThread.DangerousGetHandle());
|
||||
DebugInstance.MainProcess.Resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +109,26 @@ namespace CxbxDebugger
|
|||
return false;
|
||||
}
|
||||
|
||||
static string CxbxDebuggerPrefix = "CxbxDebugger! ";
|
||||
|
||||
|
||||
public override void OnDebugOutput(string Message)
|
||||
{
|
||||
if (Message.StartsWith(CxbxDebuggerPrefix))
|
||||
{
|
||||
SetupHLECacheProvider(Message.Substring(CxbxDebuggerPrefix.Length));
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupHLECacheProvider(string Filename)
|
||||
{
|
||||
var Provider = new HLECacheProvider();
|
||||
if( Provider.Load(Filename) )
|
||||
{
|
||||
SymbolSrv.RegisterProvider(Provider);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Launch()
|
||||
{
|
||||
if (CanLaunch() == false)
|
||||
|
@ -137,9 +155,28 @@ namespace CxbxDebugger
|
|||
if (bRet == true)
|
||||
{
|
||||
// Store these so they can be marshalled, and closed correctly
|
||||
// TODO Move to Debugger* classes
|
||||
hProcess = new WinProcesses.SafeProcessHandle(stProcessInfo.hProcess);
|
||||
hThread = new WinProcesses.SafeThreadHandle(stProcessInfo.hThread);
|
||||
|
||||
var Process = new DebuggerProcess();
|
||||
|
||||
Process.Handle = stProcessInfo.hProcess;
|
||||
Process.ProcessID = (uint)stProcessInfo.dwProcessId;
|
||||
|
||||
var Thread = new DebuggerThread(Process);
|
||||
|
||||
Thread.Handle = stProcessInfo.hThread;
|
||||
Thread.ThreadID = NativeMethods.GetThreadId(Thread.Handle);
|
||||
|
||||
Process.Threads.Add(Thread);
|
||||
Process.MainThread = Thread;
|
||||
|
||||
DebugInstance = new DebuggerInstance(Process);
|
||||
|
||||
// Register the instance to track thread creation
|
||||
RegisterEventListener(DebugInstance);
|
||||
|
||||
State = RunState.Running;
|
||||
}
|
||||
|
||||
|
@ -173,8 +210,10 @@ namespace CxbxDebugger
|
|||
|
||||
private string ReadProcessString(IntPtr NamePtr, uint Length, bool Unicode)
|
||||
{
|
||||
string resultStr = "";
|
||||
|
||||
if (Length == 0 || Length > 512)
|
||||
return "";
|
||||
return resultStr;
|
||||
|
||||
byte[] buffer = new byte[Length];
|
||||
|
||||
|
@ -193,15 +232,18 @@ namespace CxbxDebugger
|
|||
// FIXME Questionable Unicode support here
|
||||
if (Unicode)
|
||||
{
|
||||
return Encoding.Unicode.GetString(buffer, 0, (int)numRead);
|
||||
resultStr = Encoding.Unicode.GetString(buffer, 0, (int)numRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Encoding.ASCII.GetString(buffer, 0, (int)numRead);
|
||||
// TODO Investigate why the read length includes the nul-terminator
|
||||
if (numRead > 1) --numRead;
|
||||
|
||||
resultStr = Encoding.ASCII.GetString(buffer, 0, (int)numRead);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
private uint GetMemory(IntPtr addr)
|
||||
|
@ -223,61 +265,46 @@ namespace CxbxDebugger
|
|||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
private void BuildCallstack()
|
||||
private void HandleCreateThread(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
// Skip if we have nothing to report to
|
||||
if (EventListeners.Count == 0)
|
||||
return;
|
||||
var DebugInfo = DebugEvent.CreateThread;
|
||||
|
||||
bool Result = NativeMethods.GetThreadContext(hThread.DangerousGetHandle(), ref lastReadCtxt);
|
||||
if (!Result)
|
||||
{
|
||||
// TODO: Handle this
|
||||
return;
|
||||
}
|
||||
var Thread = new DebuggerThread(DebugInstance.MainProcess);
|
||||
|
||||
var ebp = lastReadCtxt.ebp;
|
||||
|
||||
var Callstack = new DebuggerCallstack();
|
||||
Callstack.AddFrame(new DebuggerStackFrame(new IntPtr(ebp), new IntPtr(lastReadCtxt.eip)));
|
||||
|
||||
do
|
||||
{
|
||||
var ReturnAddr = GetMemory(new IntPtr(ebp + 4));
|
||||
ebp = GetMemory(new IntPtr(ebp));
|
||||
|
||||
if (ebp == 0 || ReturnAddr == ebp)
|
||||
break;
|
||||
|
||||
Callstack.AddFrame(new DebuggerStackFrame(new IntPtr(ebp), new IntPtr(ReturnAddr)));
|
||||
}
|
||||
while (!Callstack.HasEnoughFrames);
|
||||
Thread.Handle = DebugInfo.hThread;
|
||||
Thread.ThreadID = Thread.ThreadID = NativeMethods.GetThreadId(Thread.Handle);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnCallstack(Callstack);
|
||||
EvtListener.OnThreadCreate(Thread);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleExitThread(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
var DebugInfo = DebugEvent.ExitThread;
|
||||
|
||||
var TargetThread = DebugInstance.MainProcess.Threads.Find(Thread => Thread.ThreadID == DebugEvent.dwThreadId);
|
||||
//uint ExitCode = DebugInfo.dwExitCode;
|
||||
|
||||
if (TargetThread != null)
|
||||
{
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnThreadExit(TargetThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCreateProcess(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
// TODO Investigate why this is throwing an exception converting to this type
|
||||
//var DebugInfo = DebugEvent.CreateProcessInfo;
|
||||
var DebugInfo = DebugEvent.CreateProcessInfo;
|
||||
|
||||
var Process = new DebuggerProcess();
|
||||
|
||||
//DebugInfo.hFile
|
||||
//DebugInfo.hProcess
|
||||
//DebugInfo.hThread
|
||||
|
||||
//DebugInfo.lpBaseOfImage
|
||||
//DebugInfo.lpStartAddress
|
||||
|
||||
ProcessList.Add(Process);
|
||||
// Stub
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnProcessCreate(Process);
|
||||
EvtListener.OnProcessCreate(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +312,7 @@ namespace CxbxDebugger
|
|||
{
|
||||
var DebugInfo = DebugEvent.ExitProcess;
|
||||
|
||||
//DebugInfo.dwExitCode
|
||||
// Stub
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
|
@ -300,8 +327,7 @@ namespace CxbxDebugger
|
|||
var Module = new DebuggerModule();
|
||||
|
||||
Module.Path = ResolveProcessPath(DebugInfo.hFile);
|
||||
|
||||
ModuleList.Add(Module);
|
||||
Module.ImageBase = DebugInfo.lpBaseOfDll;
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
|
@ -313,11 +339,14 @@ namespace CxbxDebugger
|
|||
{
|
||||
var DebugInfo = DebugEvent.UnloadDll;
|
||||
|
||||
//DebugInfo.lpBaseOfDll
|
||||
var TargetModule = DebugInstance.MainProcess.Modules.Find(Module => Module.ImageBase == DebugInfo.lpBaseOfDll);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
if (TargetModule != null)
|
||||
{
|
||||
EvtListener.OnModuleUnloaded(null);
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnModuleUnloaded(TargetModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +364,7 @@ namespace CxbxDebugger
|
|||
|
||||
public void Run()
|
||||
{
|
||||
WinDebug.DEBUG_EVENT DbgEvt;
|
||||
WinDebug.DEBUG_EVENT DbgEvt = new WinDebug.DEBUG_EVENT();
|
||||
|
||||
WinDebug.CONTINUE_STATUS ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
bool bContinue = true;
|
||||
|
@ -353,17 +382,37 @@ namespace CxbxDebugger
|
|||
|
||||
switch (DbgEvt.dwDebugEventCode)
|
||||
{
|
||||
case WinDebug.DEBUG_EVENT_CODE.EXCEPTION_DEBUG_EVENT:
|
||||
{
|
||||
// TODO: Handle
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.CREATE_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
HandleCreateThread(DbgEvt);
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.CREATE_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
// TODO: Limit support for multiple processes
|
||||
HandleCreateProcess(DbgEvt);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.EXIT_THREAD_DEBUG_EVENT:
|
||||
{
|
||||
HandleExitThread(DbgEvt);
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.EXIT_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
HandleExitProcess(DbgEvt);
|
||||
|
||||
// XX temp
|
||||
// XX Temporary
|
||||
bContinue = false;
|
||||
}
|
||||
break;
|
||||
|
@ -371,29 +420,24 @@ namespace CxbxDebugger
|
|||
case WinDebug.DEBUG_EVENT_CODE.LOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
HandleLoadDll(DbgEvt);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.UNLOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
HandleUnloadDll(DbgEvt);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.OUTPUT_DEBUG_STRING_EVENT:
|
||||
{
|
||||
HandleOutputDebugString(DbgEvt);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.EXCEPTION_DEBUG_EVENT:
|
||||
case WinDebug.DEBUG_EVENT_CODE.RIP_EVENT:
|
||||
{
|
||||
// TODO: Handle properly
|
||||
|
||||
BuildCallstack();
|
||||
// TODO: Handle
|
||||
}
|
||||
break;
|
||||
}
|
|
@ -1,20 +1,31 @@
|
|||
using System;
|
||||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerStackFrame
|
||||
{
|
||||
public IntPtr BasePointer { get; }
|
||||
public IntPtr CodeAddress { get; }
|
||||
public IntPtr PC { get; }
|
||||
public IntPtr Base { get; }
|
||||
public IntPtr Stack { get; }
|
||||
|
||||
public DebuggerStackFrame(IntPtr Base, IntPtr CodeAddr)
|
||||
// TOOD Resolve symbol for this frame
|
||||
|
||||
public DebuggerStackFrame(IntPtr EIP, IntPtr EBP, IntPtr ESP)
|
||||
{
|
||||
BasePointer = Base;
|
||||
CodeAddress = CodeAddr;
|
||||
PC = EIP;
|
||||
Base = EBP;
|
||||
Stack = ESP;
|
||||
}
|
||||
|
||||
public DebuggerStackFrame(IntPtr EIP, IntPtr EBP)
|
||||
{
|
||||
PC = EIP;
|
||||
Base = EBP;
|
||||
Stack = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +53,7 @@ namespace CxbxDebugger
|
|||
}
|
||||
}
|
||||
|
||||
// TODO Rename this property
|
||||
public bool HasEnoughFrames
|
||||
{
|
||||
get
|
|
@ -5,10 +5,6 @@ namespace CxbxDebugger
|
|||
{
|
||||
public abstract class DebuggerEventListener
|
||||
{
|
||||
public DebuggerEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnDebugStart() { }
|
||||
public virtual void OnDebugEnd() { }
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerInstance : DebuggerEventListener
|
||||
{
|
||||
public List<DebuggerProcess> Processes { get; set; }
|
||||
|
||||
public DebuggerProcess MainProcess { get; set; }
|
||||
public DebuggerThread CurrentThread { get; set; }
|
||||
|
||||
public DebuggerInstance(DebuggerProcess InitialProcess)
|
||||
{
|
||||
Processes = new List<DebuggerProcess>();
|
||||
Processes.Add(InitialProcess);
|
||||
|
||||
MainProcess = InitialProcess;
|
||||
CurrentThread = InitialProcess.MainThread;
|
||||
}
|
||||
|
||||
public override void OnThreadCreate(DebuggerThread Thread)
|
||||
{
|
||||
MainProcess.Threads.Add(Thread);
|
||||
}
|
||||
|
||||
public override void OnThreadExit(DebuggerThread Thread)
|
||||
{
|
||||
MainProcess.Threads.Remove(Thread);
|
||||
}
|
||||
|
||||
public override void OnModuleLoaded(DebuggerModule Module)
|
||||
{
|
||||
MainProcess.Modules.Add(Module);
|
||||
}
|
||||
|
||||
public override void OnModuleUnloaded(DebuggerModule Module)
|
||||
{
|
||||
MainProcess.Modules.Remove(Module);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerModule
|
||||
{
|
||||
public IntPtr ImageBase { get; set; }
|
||||
public string Path { get; set; }
|
||||
|
||||
// Based on DebugProcessModule
|
||||
public DebuggerModule()
|
||||
{
|
||||
ImageBase = IntPtr.Zero;
|
||||
Path = "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using WinProcesses = VsChromium.Core.Win32.Processes;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerProcess
|
||||
{
|
||||
public IntPtr Handle { get; set; }
|
||||
public uint ProcessID { get; set; }
|
||||
|
||||
public List<DebuggerModule> Modules { get; set; }
|
||||
public List<DebuggerThread> Threads { get; set; }
|
||||
|
||||
public DebuggerModule MainModule { get; set; }
|
||||
public DebuggerThread MainThread { get; set; }
|
||||
|
||||
// Based on DebugProcess
|
||||
public DebuggerProcess()
|
||||
{
|
||||
Handle = IntPtr.Zero;
|
||||
ProcessID = 0;
|
||||
|
||||
Modules = new List<DebuggerModule>();
|
||||
Threads = new List<DebuggerThread>();
|
||||
|
||||
MainModule = null;
|
||||
MainThread = null;
|
||||
}
|
||||
|
||||
public void Suspend()
|
||||
{
|
||||
// TODO Thread may already be in a non-suspended state
|
||||
|
||||
foreach (DebuggerThread Thread in Threads)
|
||||
{
|
||||
WinProcesses.NativeMethods.SuspendThread(Thread.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
// TODO Thread may already be in a non-suspended state
|
||||
|
||||
foreach (DebuggerThread Thread in Threads)
|
||||
{
|
||||
WinProcesses.NativeMethods.ResumeThread(Thread.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public uint ReadMemory(IntPtr addr)
|
||||
{
|
||||
byte[] buffer = new byte[4];
|
||||
|
||||
uint numRead = 0;
|
||||
WinProcesses.NativeMethods.ReadProcessMemory
|
||||
(
|
||||
Handle,
|
||||
addr,
|
||||
buffer,
|
||||
4,
|
||||
out numRead
|
||||
);
|
||||
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerThread
|
||||
{
|
||||
public DebuggerProcess OwningProcess { get; set; }
|
||||
|
||||
public IntPtr Handle { get; set; }
|
||||
public uint ThreadID { get; set; }
|
||||
public IntPtr StartAddress { get; set; }
|
||||
public IntPtr ThreadBase { get; set; }
|
||||
|
||||
CONTEXT_x86 ContextCache = new CONTEXT_x86
|
||||
{
|
||||
ContextFlags =
|
||||
ContextFlags.CONTEXT_i386 |
|
||||
ContextFlags.CONTEXT_CONTROL |
|
||||
ContextFlags.CONTEXT_INTEGER |
|
||||
ContextFlags.CONTEXT_SEGMENTS
|
||||
};
|
||||
|
||||
DebuggerCallstack CallstackCache = new DebuggerCallstack();
|
||||
|
||||
// Based on DebugThread
|
||||
public DebuggerThread(DebuggerProcess Owner)
|
||||
{
|
||||
OwningProcess = Owner;
|
||||
|
||||
Handle = IntPtr.Zero;
|
||||
ThreadID = 0;
|
||||
StartAddress = IntPtr.Zero;
|
||||
ThreadBase = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public void UpdateContext()
|
||||
{
|
||||
bool Result = NativeMethods.GetThreadContext(Handle, ref ContextCache);
|
||||
if (!Result)
|
||||
return;
|
||||
|
||||
var ebp = ContextCache.ebp;
|
||||
|
||||
CallstackCache = new DebuggerCallstack();
|
||||
|
||||
CallstackCache.AddFrame(new DebuggerStackFrame(new IntPtr(ContextCache.eip), new IntPtr(ebp), new IntPtr(ContextCache.esp)));
|
||||
|
||||
do
|
||||
{
|
||||
var ReturnAddr = OwningProcess.ReadMemory(new IntPtr(ebp + 4));
|
||||
ebp = OwningProcess.ReadMemory(new IntPtr(ebp));
|
||||
|
||||
if (ebp == 0 || ReturnAddr == ebp)
|
||||
break;
|
||||
|
||||
CallstackCache.AddFrame(new DebuggerStackFrame(new IntPtr(ReturnAddr), new IntPtr(ebp)));
|
||||
}
|
||||
while (!CallstackCache.HasEnoughFrames);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerModule
|
||||
{
|
||||
public string Path { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerProcess
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerThread
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ namespace CxbxDebugger
|
|||
SetDebugProcessActive(false);
|
||||
|
||||
// TODO: Wait for user to start this?
|
||||
StartDebugging();
|
||||
//StartDebugging();
|
||||
}
|
||||
|
||||
private void StartDebugging()
|
||||
|
@ -182,21 +182,37 @@ namespace CxbxDebugger
|
|||
frm.DebugEvent("Ended debugging session");
|
||||
}
|
||||
|
||||
public override void OnThreadCreate(DebuggerThread Thread)
|
||||
{
|
||||
frm.DebugEvent(string.Format("Thread created {0}", Thread.ThreadID));
|
||||
}
|
||||
|
||||
public override void OnThreadExit(DebuggerThread Thread)
|
||||
{
|
||||
frm.DebugEvent(string.Format("Thread exited {0}", Thread.ThreadID));
|
||||
}
|
||||
|
||||
public override void OnModuleLoaded(DebuggerModule Module)
|
||||
{
|
||||
frm.DebugEvent("Loading module: " + Module.Path);
|
||||
frm.DebugEvent(string.Format("Loaded module \"{0}\"", Module.Path));
|
||||
}
|
||||
|
||||
public override void OnModuleUnloaded(DebuggerModule Module)
|
||||
{
|
||||
frm.DebugEvent(string.Format("Unloaded module \"{0}\"", Module.Path));
|
||||
}
|
||||
|
||||
public override void OnDebugOutput(string Message)
|
||||
{
|
||||
frm.DebugEvent("Debug string: " + Message);
|
||||
frm.DebugEvent(string.Format("OutputDebugString \"{0}\"", Message));
|
||||
}
|
||||
|
||||
// TODO Update DebuggerStackFrame to query symbols
|
||||
public override void OnCallstack(DebuggerCallstack Callstack)
|
||||
{
|
||||
foreach( DebuggerStackFrame StackFrame in Callstack.StackFrames)
|
||||
{
|
||||
var stackFrameStr = string.Format("{0:X8} and {1:X8}", (uint)StackFrame.BasePointer, (uint)StackFrame.CodeAddress);
|
||||
var stackFrameStr = string.Format("{0:X8} --> {1:X8}", (uint)StackFrame.Base, (uint)StackFrame.PC);
|
||||
frm.DebugEvent("Callstack: " + stackFrameStr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CxbxDebugger.TheadHelpers
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
[Flags]
|
||||
public enum ContextFlags : uint
|
||||
|
@ -263,5 +263,8 @@ namespace CxbxDebugger.TheadHelpers
|
|||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT_x86 lpContext);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint GetThreadId(IntPtr hThread);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,13 @@ namespace VsChromium.Core.Win32.Processes
|
|||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ReadProcessMemory(SafeProcessHandle hProcess, IntPtr lpBaseAddress,
|
||||
[Out] byte[] buffer, uint size, out UInt32 lpNumberOfBytesRead);
|
||||
[Out] byte[] buffer, uint size, out uint lpNumberOfBytesRead);
|
||||
|
||||
// x1nix: added
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
|
||||
[Out] byte[] buffer, uint size, out uint lpNumberOfBytesRead);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern int NtQueryInformationProcess(SafeProcessHandle hProcess, ProcessInfoClass pic, ref ProcessBasicInformation pbi, int cb, out int pSize);
|
||||
|
|
|
@ -14,6 +14,10 @@ namespace LowLevelDesign.Win32.Windows
|
|||
[DllImport("user32.dll")]
|
||||
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
// x1nix: added
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetProcessId(IntPtr hProcess);
|
||||
|
||||
// x1nix: added
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint GetFinalPathNameByHandleW(IntPtr hFile, IntPtr lpszFilePath, uint cchFilePath = 0u, uint dwFlags = 0u);
|
||||
|
|
Loading…
Reference in New Issue