Expanded debugger event listener interface
Also removed unused Win32 files
This commit is contained in:
parent
be7c796a71
commit
8eb4fa4df8
|
@ -65,6 +65,10 @@
|
|||
<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="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -74,7 +78,6 @@
|
|||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ThreadHelpers.cs" />
|
||||
<Compile Include="Win32\ComPtr.cs" />
|
||||
<Compile Include="Win32\Constants.cs" />
|
||||
<Compile Include="Win32\Debugging\CONTINUE_STATUS.cs" />
|
||||
<Compile Include="Win32\Debugging\CREATE_PROCESS_DEBUG_INFO.cs" />
|
||||
|
@ -92,7 +95,6 @@
|
|||
<Compile Include="Win32\Debugging\RIP_INFO.cs" />
|
||||
<Compile Include="Win32\Debugging\UNLOAD_DLL_DEBUG_INFO.cs" />
|
||||
<Compile Include="Win32\Handles\NativeMethods.cs" />
|
||||
<Compile Include="Win32\HResults.cs" />
|
||||
<Compile Include="Win32\Interop\SecurityAttributes.cs" />
|
||||
<Compile Include="Win32\Jobs\IO_COUNTERS.cs" />
|
||||
<Compile Include="Win32\Jobs\JobInformationLimitFlags.cs" />
|
||||
|
|
|
@ -11,20 +11,15 @@ using CxbxDebugger.TheadHelpers;
|
|||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class Stackframe
|
||||
{
|
||||
public IntPtr BasePointer { get; }
|
||||
public IntPtr CodeAddress { get; }
|
||||
|
||||
public Stackframe(IntPtr Base, IntPtr CodeAddr)
|
||||
{
|
||||
BasePointer = Base;
|
||||
CodeAddress = CodeAddr;
|
||||
}
|
||||
}
|
||||
|
||||
public class Debugger : IDisposable
|
||||
{
|
||||
enum RunState
|
||||
{
|
||||
NotLaunched,
|
||||
Running,
|
||||
Ended
|
||||
};
|
||||
|
||||
// Cached process information
|
||||
WinProcesses.PROCESS_INFORMATION stProcessInfo = new WinProcesses.PROCESS_INFORMATION();
|
||||
WinProcesses.STARTUPINFO stStartInfo = new WinProcesses.STARTUPINFO();
|
||||
|
@ -34,8 +29,13 @@ namespace CxbxDebugger
|
|||
WinProcesses.SafeThreadHandle hThread = new WinProcesses.SafeThreadHandle();
|
||||
|
||||
string[] args = new string[] { };
|
||||
bool Running = false;
|
||||
|
||||
RunState State = RunState.NotLaunched;
|
||||
|
||||
List<DebuggerModule> ModuleList = new List<DebuggerModule>();
|
||||
List<DebuggerThread> ThreadList = new List<DebuggerThread>();
|
||||
List<DebuggerProcess> ProcessList = new List<DebuggerProcess>();
|
||||
|
||||
List<DebuggerEventListener> EventListeners = new List<DebuggerEventListener>();
|
||||
|
||||
CONTEXT_x86 lastReadCtxt = new CONTEXT_x86
|
||||
|
@ -99,8 +99,23 @@ namespace CxbxDebugger
|
|||
}
|
||||
}
|
||||
|
||||
public bool CanLaunch()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case RunState.NotLaunched:
|
||||
case RunState.Ended:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Launch()
|
||||
{
|
||||
if (CanLaunch() == false)
|
||||
throw new Exception("Unable to launch in this state");
|
||||
|
||||
var DebugCreationFlags =
|
||||
WinProcesses.ProcessCreationFlags.DEBUG_ONLY_THIS_PROCESS |
|
||||
WinProcesses.ProcessCreationFlags.CREATE_NEW_CONSOLE;
|
||||
|
@ -125,7 +140,7 @@ namespace CxbxDebugger
|
|||
hProcess = new WinProcesses.SafeProcessHandle(stProcessInfo.hProcess);
|
||||
hThread = new WinProcesses.SafeThreadHandle(stProcessInfo.hThread);
|
||||
|
||||
Running = true;
|
||||
State = RunState.Running;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
|
@ -208,7 +223,6 @@ namespace CxbxDebugger
|
|||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
|
||||
private void BuildCallstack()
|
||||
{
|
||||
// Skip if we have nothing to report to
|
||||
|
@ -222,14 +236,11 @@ namespace CxbxDebugger
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Expose as variable
|
||||
const int MaxFrames = 16;
|
||||
|
||||
var Callstack = new List<Stackframe>();
|
||||
var ebp = lastReadCtxt.ebp;
|
||||
|
||||
Callstack.Add(new Stackframe(new IntPtr(ebp), new IntPtr(lastReadCtxt.eip)));
|
||||
|
||||
var Callstack = new DebuggerCallstack();
|
||||
Callstack.AddFrame(new DebuggerStackFrame(new IntPtr(ebp), new IntPtr(lastReadCtxt.eip)));
|
||||
|
||||
do
|
||||
{
|
||||
var ReturnAddr = GetMemory(new IntPtr(ebp + 4));
|
||||
|
@ -238,32 +249,97 @@ namespace CxbxDebugger
|
|||
if (ebp == 0 || ReturnAddr == ebp)
|
||||
break;
|
||||
|
||||
Callstack.Add(new Stackframe(new IntPtr(ebp), new IntPtr(ReturnAddr)));
|
||||
}
|
||||
while (Callstack.Count < MaxFrames);
|
||||
|
||||
|
||||
var strList = new List<string>(Callstack.Count);
|
||||
|
||||
foreach (Stackframe sf in Callstack)
|
||||
{
|
||||
// TODO: Resolve BasePointer to symbol database
|
||||
strList.Add(string.Format("{0:X8} and {1:X8}", (uint)sf.BasePointer, (uint)sf.CodeAddress));
|
||||
Callstack.AddFrame(new DebuggerStackFrame(new IntPtr(ebp), new IntPtr(ReturnAddr)));
|
||||
}
|
||||
while (!Callstack.HasEnoughFrames);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnCallstack(strList.ToArray());
|
||||
EvtListener.OnCallstack(Callstack);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCreateProcess(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
// TODO Investigate why this is throwing an exception converting to this type
|
||||
//var DebugInfo = DebugEvent.CreateProcessInfo;
|
||||
|
||||
var Process = new DebuggerProcess();
|
||||
|
||||
//DebugInfo.hFile
|
||||
//DebugInfo.hProcess
|
||||
//DebugInfo.hThread
|
||||
|
||||
//DebugInfo.lpBaseOfImage
|
||||
//DebugInfo.lpStartAddress
|
||||
|
||||
ProcessList.Add(Process);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnProcessCreate(Process);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleExitProcess(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
var DebugInfo = DebugEvent.ExitProcess;
|
||||
|
||||
//DebugInfo.dwExitCode
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnProcessExit(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleLoadDll(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
var DebugInfo = DebugEvent.LoadDll;
|
||||
|
||||
var Module = new DebuggerModule();
|
||||
|
||||
Module.Path = ResolveProcessPath(DebugInfo.hFile);
|
||||
|
||||
ModuleList.Add(Module);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnModuleLoaded(Module);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleUnloadDll(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
var DebugInfo = DebugEvent.UnloadDll;
|
||||
|
||||
//DebugInfo.lpBaseOfDll
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnModuleUnloaded(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleOutputDebugString(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
{
|
||||
var DebugInfo = DebugEvent.DebugString;
|
||||
|
||||
string debugString = ReadProcessString(DebugInfo.lpDebugStringData, DebugInfo.nDebugStringLength, DebugInfo.fUnicode == 1);
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnDebugOutput(debugString);
|
||||
}
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
WinDebug.DEBUG_EVENT DbgEvt;
|
||||
|
||||
WinDebug.CONTINUE_STATUS ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
bool bContinue = true;
|
||||
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnDebugStart();
|
||||
|
@ -279,67 +355,37 @@ namespace CxbxDebugger
|
|||
{
|
||||
case WinDebug.DEBUG_EVENT_CODE.CREATE_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
// TODO: Handle properly, storing process info
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnProcessCreate();
|
||||
}
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
HandleCreateProcess(DbgEvt);
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.EXIT_PROCESS_DEBUG_EVENT:
|
||||
{
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnProcessExit();
|
||||
}
|
||||
HandleExitProcess(DbgEvt);
|
||||
|
||||
// XX temp
|
||||
bContinue = false;
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.LOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
// TODO: Handle properly
|
||||
|
||||
string Name = ResolveProcessPath(DbgEvt.LoadDll.hFile);
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnModuleLoaded(Name);
|
||||
}
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
HandleLoadDll(DbgEvt);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.UNLOAD_DLL_DEBUG_EVENT:
|
||||
{
|
||||
// TODO: Handle properly, looking up module being unloaded
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnModuleUnloaded();
|
||||
}
|
||||
HandleUnloadDll(DbgEvt);
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WinDebug.DEBUG_EVENT_CODE.OUTPUT_DEBUG_STRING_EVENT:
|
||||
{
|
||||
string dbgStr = ReadProcessString(DbgEvt.DebugString.lpDebugStringData, DbgEvt.DebugString.nDebugStringLength, DbgEvt.DebugString.fUnicode == 1);
|
||||
//Console.WriteLine(dbgStr);
|
||||
|
||||
foreach(DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
EvtListener.OnDebugOutput(dbgStr);
|
||||
}
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
HandleOutputDebugString(DbgEvt);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -348,24 +394,14 @@ namespace CxbxDebugger
|
|||
// TODO: Handle properly
|
||||
|
||||
BuildCallstack();
|
||||
|
||||
// Temporary. Should wait until owning systems are happy to continue
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// For any other events, just continue
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Continue on our merry way
|
||||
// TODO: Wait until our handlers are happy to continue
|
||||
WinDebug.NativeMethods.ContinueDebugEvent(DbgEvt.dwProcessId, DbgEvt.dwThreadId, ContinueStatus);
|
||||
}
|
||||
|
||||
State = RunState.Ended;
|
||||
|
||||
foreach (DebuggerEventListener EvtListener in EventListeners)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
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 DebuggerStackFrame(IntPtr Base, IntPtr CodeAddr)
|
||||
{
|
||||
BasePointer = Base;
|
||||
CodeAddress = CodeAddr;
|
||||
}
|
||||
}
|
||||
|
||||
public class DebuggerCallstack
|
||||
{
|
||||
int NumSupportedFrames = 16;
|
||||
public List<DebuggerStackFrame> StackFrames { get; }
|
||||
|
||||
public DebuggerCallstack()
|
||||
{
|
||||
StackFrames = new List<DebuggerStackFrame>(NumSupportedFrames);
|
||||
}
|
||||
|
||||
public DebuggerCallstack(int MaxFrames)
|
||||
{
|
||||
NumSupportedFrames = MaxFrames;
|
||||
StackFrames = new List<DebuggerStackFrame>(NumSupportedFrames);
|
||||
}
|
||||
|
||||
public void AddFrame(DebuggerStackFrame StackFrame)
|
||||
{
|
||||
if (!HasEnoughFrames)
|
||||
{
|
||||
StackFrames.Add(StackFrame);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasEnoughFrames
|
||||
{
|
||||
get
|
||||
{
|
||||
return StackFrames.Count < NumSupportedFrames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,16 +12,16 @@ namespace CxbxDebugger
|
|||
public virtual void OnDebugStart() { }
|
||||
public virtual void OnDebugEnd() { }
|
||||
|
||||
public virtual void OnProcessCreate() { }
|
||||
public virtual void OnProcessExit() { }
|
||||
public virtual void OnProcessCreate(DebuggerProcess Process) { }
|
||||
public virtual void OnProcessExit(DebuggerProcess Process) { }
|
||||
|
||||
public virtual void OnThreadCreate() { }
|
||||
public virtual void OnThreadExit() { }
|
||||
public virtual void OnThreadCreate(DebuggerThread Thread) { }
|
||||
public virtual void OnThreadExit(DebuggerThread Thread) { }
|
||||
|
||||
public virtual void OnModuleLoaded(string ModuleName) { }
|
||||
public virtual void OnModuleUnloaded() { }
|
||||
public virtual void OnModuleLoaded(DebuggerModule Module) { }
|
||||
public virtual void OnModuleUnloaded(DebuggerModule Module) { }
|
||||
|
||||
public virtual void OnCallstack(string[] Callstack) { }
|
||||
public virtual void OnCallstack(DebuggerCallstack Callstack) { }
|
||||
|
||||
public virtual void OnDebugOutput(string Message) { }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerProcess
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public class DebuggerThread
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -114,17 +114,19 @@ namespace CxbxDebugger
|
|||
|
||||
public void DebugEvent(string Message)
|
||||
{
|
||||
if( lbConsole.InvokeRequired )
|
||||
string MessageStamped = string.Format("[{0}] {1}", DateTime.Now.ToLongTimeString(), Message);
|
||||
|
||||
if ( lbConsole.InvokeRequired )
|
||||
{
|
||||
// Ensure we Add items on the right thread
|
||||
lbConsole.Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
lbConsole.Items.Add(Message);
|
||||
lbConsole.Items.Insert(0, MessageStamped);
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
lbConsole.Items.Add(Message);
|
||||
lbConsole.Items.Insert(0, MessageStamped);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,9 +182,9 @@ namespace CxbxDebugger
|
|||
frm.DebugEvent("Ended debugging session");
|
||||
}
|
||||
|
||||
public override void OnModuleLoaded(string ModuleName)
|
||||
public override void OnModuleLoaded(DebuggerModule Module)
|
||||
{
|
||||
frm.DebugEvent("Loading module: " + ModuleName);
|
||||
frm.DebugEvent("Loading module: " + Module.Path);
|
||||
}
|
||||
|
||||
public override void OnDebugOutput(string Message)
|
||||
|
@ -190,12 +192,12 @@ namespace CxbxDebugger
|
|||
frm.DebugEvent("Debug string: " + Message);
|
||||
}
|
||||
|
||||
public override void OnCallstack(string[] Callstack)
|
||||
public override void OnCallstack(DebuggerCallstack Callstack)
|
||||
{
|
||||
// Placeholder display
|
||||
foreach( string str in Callstack)
|
||||
foreach( DebuggerStackFrame StackFrame in Callstack.StackFrames)
|
||||
{
|
||||
frm.DebugEvent("Callstack: " + str);
|
||||
var stackFrameStr = string.Format("{0:X8} and {1:X8}", (uint)StackFrame.BasePointer, (uint)StackFrame.CodeAddress);
|
||||
frm.DebugEvent("Callstack: " + stackFrameStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace VsChromium.Core.Win32 {
|
||||
public struct ComPtr<T> : IDisposable where T : class {
|
||||
private T ptr;
|
||||
|
||||
public ComPtr(T ptr) {
|
||||
Debug.Assert(ptr == null || Marshal.IsComObject(ptr));
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public T Ptr { get { return ptr; } }
|
||||
|
||||
public void Dispose() {
|
||||
if (ptr != null)
|
||||
Marshal.ReleaseComObject(ptr);
|
||||
|
||||
ptr = null;
|
||||
}
|
||||
|
||||
public T Detach() {
|
||||
T result = ptr;
|
||||
ptr = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ComPtr {
|
||||
public static ComPtr<T> Create<T>(T ptr) where T : class {
|
||||
return new ComPtr<T>(ptr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace VsChromium.Core.Win32 {
|
||||
public static class HResults {
|
||||
public const int HR_ERROR_SEM_TIMEOUT = unchecked((int)0x80070079);
|
||||
public const int HR_ERROR_NOT_SUPPORTED = unchecked((int)0x80070032);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue