Added skeleton processes debugger

Uses files from Chromium for the Win32 API
This commit is contained in:
x1nixmzeng 2018-01-02 23:21:11 +00:00
parent 984e2bd510
commit 887654f7aa
55 changed files with 2613 additions and 0 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4A68E962-3805-4376-99D3-0AC59E9BEE69}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CxbxDebugger</RootNamespace>
<AssemblyName>CxbxDebugger</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\build\win32\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\build\win32\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Debugger.cs" />
<Compile Include="DebuggerEventListener.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<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" />
<Compile Include="Win32\Debugging\CREATE_THREAD_DEBUG_INFO.cs" />
<Compile Include="Win32\Debugging\DEBUG_EVENT.cs" />
<Compile Include="Win32\Debugging\DEBUG_EVENT_CODE.cs" />
<Compile Include="Win32\Debugging\EXCEPTION_DEBUG_INFO.cs" />
<Compile Include="Win32\Debugging\EXCEPTION_RECORD.cs" />
<Compile Include="Win32\Debugging\EXIT_PROCESS_DEBUG_INFO.cs" />
<Compile Include="Win32\Debugging\EXIT_THREAD_DEBUG_INFO.cs" />
<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" />
<Compile Include="Win32\HResults.cs" />
<Compile Include="Win32\Interop\SecurityAttributes.cs" />
<Compile Include="Win32\Jobs\IO_COUNTERS.cs" />
<Compile Include="Win32\Jobs\JobInformationLimitFlags.cs" />
<Compile Include="Win32\Jobs\JobMsgInfoMessages.cs" />
<Compile Include="Win32\Jobs\JOBOBJECTINFOCLASS.cs" />
<Compile Include="Win32\Jobs\JOBOBJECT_ASSOCIATE_COMPLETION_PORT.cs" />
<Compile Include="Win32\Jobs\JOBOBJECT_BASIC_LIMIT_INFORMATION.cs" />
<Compile Include="Win32\Jobs\JOBOBJECT_EXTENDED_LIMIT_INFORMATION.cs" />
<Compile Include="Win32\Jobs\NativeMethods.cs" />
<Compile Include="Win32\LastWin32ErrorException.cs" />
<Compile Include="Win32\NtStatus.cs" />
<Compile Include="Win32\Processes\NativeEnums.cs" />
<Compile Include="Win32\Processes\NativeMethods.cs" />
<Compile Include="Win32\Processes\NativeStructs.cs" />
<Compile Include="Win32\Processes\ProcessCreationFlags.cs" />
<Compile Include="Win32\Processes\PROCESS_INFORMATION.cs" />
<Compile Include="Win32\Processes\SafeProcessHandle.cs" />
<Compile Include="Win32\Processes\SafeThreadHandle.cs" />
<Compile Include="Win32\Processes\Startupinfo.cs" />
<Compile Include="Win32\UnicodeString.cs" />
<Compile Include="Win32\Windows\NativeMethods.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,386 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System;
using System.Collections.Generic;
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 Stackframe
{
public IntPtr BasePointer { get; }
public IntPtr CodeAddress { get; }
public Stackframe(IntPtr Base, IntPtr CodeAddr)
{
BasePointer = Base;
CodeAddress = CodeAddr;
}
}
public class Debugger : IDisposable
{
// Cached process information
WinProcesses.PROCESS_INFORMATION stProcessInfo = new WinProcesses.PROCESS_INFORMATION();
WinProcesses.STARTUPINFO stStartInfo = new WinProcesses.STARTUPINFO();
// Wrapped so these can be closed automatically
WinProcesses.SafeProcessHandle hProcess = new WinProcesses.SafeProcessHandle();
WinProcesses.SafeThreadHandle hThread = new WinProcesses.SafeThreadHandle();
string[] args = new string[] { };
bool Running = false;
List<DebuggerEventListener> EventListeners = new List<DebuggerEventListener>();
CONTEXT_x86 lastReadCtxt = new CONTEXT_x86
{
ContextFlags =
ContextFlags.CONTEXT_i386 |
ContextFlags.CONTEXT_CONTROL |
ContextFlags.CONTEXT_INTEGER |
ContextFlags.CONTEXT_SEGMENTS
};
public Debugger()
{
//
}
public Debugger(string[] x_args)
{
if (x_args == null)
return;
// Copy all arguments
args = x_args;
// Keep quotes for any potential file paths
for(int i = 0; i < args.Length; ++i)
{
if( args[i].IndexOf(":\\") == 1)
{
args[i] = string.Format("\"{0}\"", args[i]);
}
}
}
public void Dispose()
{
// Destroy process
WinProcesses.NativeMethods.TerminateProcess(hProcess, 0);
// close it
hProcess.Close();
hThread.Close();
}
public void Break()
{
// This will ONLY suspend the main process
// Not ideal if there are multiple processes in play
if (!hThread.IsInvalid)
{
WinProcesses.NativeMethods.SuspendThread(hThread.DangerousGetHandle());
}
}
public void Resume()
{
if (!hThread.IsInvalid)
{
WinProcesses.NativeMethods.ResumeThread(hThread.DangerousGetHandle());
}
}
public bool Launch()
{
var DebugCreationFlags =
WinProcesses.ProcessCreationFlags.DEBUG_ONLY_THIS_PROCESS |
WinProcesses.ProcessCreationFlags.CREATE_NEW_CONSOLE;
bool bRet = WinProcesses.NativeMethods.CreateProcess
(
null,
new StringBuilder(string.Join(" ", args)),
null,
null,
false,
DebugCreationFlags,
null,
null,
stStartInfo,
stProcessInfo
);
if (bRet == true)
{
// Store these so they can be marshalled, and closed correctly
hProcess = new WinProcesses.SafeProcessHandle(stProcessInfo.hProcess);
hThread = new WinProcesses.SafeThreadHandle(stProcessInfo.hThread);
Running = true;
}
return bRet;
}
private string ResolveProcessPath(IntPtr FileHandle)
{
string path = "";
const int bufSize = 1024;
var strPtr = Marshal.AllocHGlobal(bufSize);
uint length = LowLevelDesign.Win32.Windows.NativeMethods.GetFinalPathNameByHandleW
(
FileHandle,
strPtr,
bufSize,
0
);
if (length != 0)
{
path = Marshal.PtrToStringUni(strPtr, (int)length);
path = path.TrimStart('\\', '?');
}
Marshal.FreeHGlobal(strPtr);
return path;
}
private string ReadProcessString(IntPtr NamePtr, uint Length, bool Unicode)
{
if (Length == 0 || Length > 512)
return "";
byte[] buffer = new byte[Length];
uint numRead = 0;
WinProcesses.NativeMethods.ReadProcessMemory
(
hProcess,
NamePtr,
buffer,
Length,
out numRead
);
if( numRead == Length )
{
// FIXME Questionable Unicode support here
if (Unicode)
{
return Encoding.Unicode.GetString(buffer, 0, (int)numRead);
}
else
{
return Encoding.ASCII.GetString(buffer, 0, (int)numRead);
}
}
return "";
}
private uint GetMemory(IntPtr addr)
{
// TODO: Template this for different sizes
byte[] buffer = new byte[4];
uint numRead = 0;
WinProcesses.NativeMethods.ReadProcessMemory
(
hProcess,
addr,
buffer,
4,
out numRead
);
return BitConverter.ToUInt32(buffer, 0);
}
private void BuildCallstack()
{
// Skip if we have nothing to report to
if (EventListeners.Count == 0)
return;
bool Result = NativeMethods.GetThreadContext(hThread.DangerousGetHandle(), ref lastReadCtxt);
if (!Result)
{
// TODO: Handle this
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)));
do
{
var ReturnAddr = GetMemory(new IntPtr(ebp + 4));
ebp = GetMemory(new IntPtr(ebp));
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));
}
foreach (DebuggerEventListener EvtListener in EventListeners)
{
EvtListener.OnCallstack(strList.ToArray());
}
}
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();
}
// Loop until told to stop
while (bContinue == true)
{
// Pause until a debug event notification happens
bContinue = WinDebug.NativeMethods.WaitForDebugEvent(out DbgEvt, VsChromium.Core.Win32.Constants.INFINITE);
switch (DbgEvt.dwDebugEventCode)
{
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;
}
break;
case WinDebug.DEBUG_EVENT_CODE.EXIT_PROCESS_DEBUG_EVENT:
{
foreach (DebuggerEventListener EvtListener in EventListeners)
{
EvtListener.OnProcessExit();
}
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;
}
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();
}
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;
}
break;
case WinDebug.DEBUG_EVENT_CODE.EXCEPTION_DEBUG_EVENT:
{
// 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);
}
foreach (DebuggerEventListener EvtListener in EventListeners)
{
EvtListener.OnDebugEnd();
}
}
public void RegisterEventListener(DebuggerEventListener EventListener)
{
EventListeners.Add(EventListener);
}
public void UnregisterEventListener(DebuggerEventListener EventListener)
{
EventListeners.Remove(EventListener);
}
}
}

View File

@ -0,0 +1,28 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
namespace CxbxDebugger
{
public abstract class DebuggerEventListener
{
public DebuggerEventListener()
{
}
public virtual void OnDebugStart() { }
public virtual void OnDebugEnd() { }
public virtual void OnProcessCreate() { }
public virtual void OnProcessExit() { }
public virtual void OnThreadCreate() { }
public virtual void OnThreadExit() { }
public virtual void OnModuleLoaded(string ModuleName) { }
public virtual void OnModuleUnloaded() { }
public virtual void OnCallstack(string[] Callstack) { }
public virtual void OnDebugOutput(string Message) { }
}
}

102
src/CxbxDebugger/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,102 @@
namespace CxbxDebugger
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(63, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Restart Session";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(81, 12);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(63, 23);
this.button2.TabIndex = 1;
this.button2.Text = "Suspend";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(150, 12);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(63, 23);
this.button3.TabIndex = 1;
this.button3.Text = "Resume";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// listBox1
//
this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(12, 47);
this.listBox1.Name = "listBox1";
this.listBox1.ScrollAlwaysVisible = true;
this.listBox1.Size = new System.Drawing.Size(506, 212);
this.listBox1.TabIndex = 2;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(530, 271);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Cxbx-Reloaded Debugger";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form1_FormClosed);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.ListBox listBox1;
}
}

168
src/CxbxDebugger/Form1.cs Normal file
View File

@ -0,0 +1,168 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System;
using System.Windows.Forms;
using System.Threading;
using System.Collections.Generic;
namespace CxbxDebugger
{
public partial class Form1 : Form
{
Thread DebuggerWorkerThread;
Debugger DebuggerInst;
string[] CachedArgs;
public Form1()
{
InitializeComponent();
string[] args = Environment.GetCommandLineArgs();
// Arguments are expected before the Form is created
if (args.Length < 2 ) {
throw new Exception("Incorrect usage");
}
var items = new List<string>(args.Length - 1);
for (int i = 1; i < args.Length; ++i)
{
items.Add(args[i]);
//listBox1.Items.Add("Arg: " + args[i]);
}
CachedArgs = items.ToArray();
// TODO: Wait for user to start this?
StartDebugging();
}
private void StartDebugging()
{
bool Create = false;
if (DebuggerWorkerThread == null)
{
// First launch
Create = true;
}
else if (DebuggerWorkerThread.ThreadState == System.Threading.ThreadState.Stopped)
{
// Further launches
Create = true;
}
if (Create)
{
// Create debugger instance
DebuggerInst = new Debugger(CachedArgs);
DebuggerInst.RegisterEventListener(new DebuggerFormEvents(this));
// Setup new debugger thread
DebuggerWorkerThread = new Thread(x =>
{
if (DebuggerInst.Launch())
{
DebuggerInst.Run();
}
});
DebuggerWorkerThread.Name = "CxbxDebugger";
DebuggerWorkerThread.Start();
}
}
private void button1_Click(object sender, EventArgs e)
{
StartDebugging();
}
private void button2_Click(object sender, EventArgs e)
{
if (DebuggerInst != null)
{
DebuggerInst.Break();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (DebuggerInst != null)
{
DebuggerInst.Resume();
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (DebuggerWorkerThread != null)
{
if (DebuggerWorkerThread.ThreadState == ThreadState.Running)
{
DebuggerWorkerThread.Abort();
}
}
if(DebuggerInst!= null)
{
DebuggerInst.Dispose();
}
}
public void DebugEvent(string Message)
{
if( listBox1.InvokeRequired )
{
// Ensure we Add items on the right thread
listBox1.Invoke(new MethodInvoker(delegate ()
{
listBox1.Items.Add(Message);
}));
}
else
{
listBox1.Items.Add(Message);
}
}
}
class DebuggerFormEvents : DebuggerEventListener
{
readonly Form1 frm;
public DebuggerFormEvents(Form1 main)
{
frm = main;
}
public override void OnDebugStart()
{
frm.DebugEvent("Started debugging session");
}
public override void OnDebugEnd()
{
frm.DebugEvent("Ended debugging session");
}
public override void OnModuleLoaded(string ModuleName)
{
frm.DebugEvent("Loading module: " + ModuleName);
}
public override void OnDebugOutput(string Message)
{
frm.DebugEvent("Debug string: " + Message);
}
public override void OnCallstack(string[] Callstack)
{
// Placeholder display
foreach( string str in Callstack)
{
frm.DebugEvent("Callstack: " + str);
}
}
}
}

120
src/CxbxDebugger/Form1.resx Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,33 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System;
using System.Windows.Forms;
namespace CxbxDebugger
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
if( args.Length == 1 )
{
// TODO: Valid usage message
MessageBox.Show("The debugger must be launched from Cxbx with the child process arguments", "Cxbx-Debugger", MessageBoxButtons.OK, MessageBoxIcon.Information);
Application.Exit();
}
else
{
Application.Run(new Form1());
}
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("cxbxdbg")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("cxbxdbg")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4a68e962-3805-4376-99d3-0ac59e9bee69")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CxbxDebugger.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CxbxDebugger.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CxbxDebugger.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,267 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System;
using System.Runtime.InteropServices;
namespace CxbxDebugger.TheadHelpers
{
[Flags]
public enum ContextFlags : uint
{
/// <summary>
/// Both working for 386 and 486 CPUs
/// </summary>
CONTEXT_i386 = 0x00010000u,
/// <summary>
/// SS:SP, CS:IP, FLAGS, BP
/// </summary>
CONTEXT_CONTROL = (CONTEXT_i386 | 0x00000001u),
/// <summary>
/// AX, BX, CX, DX, SI, DI
/// </summary>
CONTEXT_INTEGER = (CONTEXT_i386 | 0x00000002u),
/// <summary>
/// DS, ES, FS, GS
/// </summary>
CONTEXT_SEGMENTS = (CONTEXT_i386 | 0x00000004u),
/// <summary>
/// 387 state
/// </summary>
CONTEXT_FLOATING_POINT = (CONTEXT_i386 | 0x00000008u),
/// <summary>
/// DB 0-3,6,7
/// </summary>
CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | 0x00000010u),
/// <summary>
/// cpu specific extensions
/// </summary>
CONTEXT_EXTENDED_REGISTERS = (CONTEXT_i386 | 0x00000020u),
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS,
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS |
CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS |
CONTEXT_EXTENDED_REGISTERS
}
[Flags]
public enum Extendedx86ContextFlags : uint
{
/// <summary>
/// Carry Flag. Set if the last arithmetic operation carried
/// (addition) or borrowed (subtraction) a bit beyond the
/// size of the register. This is then checked when the
/// operation is followed with an add-with-carry or
/// subtract-with-borrow to deal with values too large
/// for just one register to contain.
/// </summary>
Carry = 0,
/// <summary>
/// Parity Flag. Set if the number of set bits in the
/// least significant byte is a multiple of 2.
/// </summary>
Parity = 2,
/// <summary>
/// Adjust Flag. Carry of Binary Code Decimal (BCD) numbers arithmetic operations.
/// </summary>
Adjust = 1u << 4,
/// <summary>
/// Zero Flag. Set if the result of an operation is Zero (0).
/// </summary>
Zero = 1u << 6,
/// <summary>
/// Sign Flag. Set if the result of an operation is negative.
/// </summary>
Sign = 1u << 7,
/// <summary>
/// Trap Flag. Set if step by step debugging.
/// </summary>
Trap = 1u << 8,
/// <summary>
/// Interruption Flag. Set if interrupts are enabled.
/// </summary>
Interruption = 1u << 9,
/// <summary>
/// Direction Flag. Stream direction. If set, string operations
/// will decrement their pointer rather than incrementing it,
/// reading memory backwards.
/// </summary>
Direction = 1u << 10,
/// <summary>
/// Overflow Flag. Set if signed arithmetic operations result
/// in a value too large for the register to contain.
/// </summary>
Overflow = 1u << 11,
/// <summary>
/// I/O Privilege Level field (2 bits). I/O Privilege Level of the current process.
/// </summary>
IOPL_firstBit = 1u << 12,
/// <summary>
/// I/O Privilege Level field (2 bits). I/O Privilege Level of the current process.
/// </summary>
IOPL_lastBit = 1u << 13,
/// <summary>
/// Nested Task flag. Controls chaining of interrupts.
/// Set if the current process is linked to the next process.
/// </summary>
NestedTask = 1u << 14,
/// <summary>
/// Resume Flag. Response to debug exceptions.
/// </summary>
Resume = 1u << 16,
/// <summary>
/// Virtual-8086 Mode. Set if in 8086 compatibility mode.
/// </summary>
Virtual8086Mode = 1u << 17,
/// <summary>
/// Alignment Check. Set if alignment checking of memory references is done.
/// </summary>
AlignmentCheck = 1u << 18,
/// <summary>
/// Virtual Interrupt Flag. Virtual image of IF.
/// </summary>
VirtualInterrupt = 1u << 19,
/// <summary>
/// Virtual Interrupt Pending flag. Set if an interrupt is pending.
/// </summary>
VirtualInterruptPending = 1u << 20,
/// <summary>
/// Identification Flag. Support for CPUID instruction if can be set.
/// </summary>
Id = 1u << 21
}
// todo: move away from here
public static class Constants
{
/// <summary>
/// Define the size of the 80387 save area, which is in the context frame.
/// </summary>
public const int SIZE_OF_80387_REGISTERS = 80;
public const int MAXIMUM_SUPPORTED_EXTENSION = 512;
}
[StructLayout(LayoutKind.Sequential)]
public struct FLOATING_SAVE_AREA
{
public uint ControlWord;
public uint StatusWord;
public uint TagWord;
public uint ErrorOffset;
public uint ErrorSelector;
public uint DataOffset;
public uint DataSelector;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.SIZE_OF_80387_REGISTERS)]
public byte[] RegisterArea;
public uint Cr0NpxState;
}
[StructLayout(LayoutKind.Sequential)]
public struct CONTEXT_x86
{
//
// The flags values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a threads context, then only that
// portion of the threads context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, then only those portions of the thread's
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
//
public ContextFlags ContextFlags;
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
public uint Dr0;
public uint Dr1;
public uint Dr2;
public uint Dr3;
public uint Dr6;
public uint Dr7;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
//
public FLOATING_SAVE_AREA FloatSave;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_SEGMENTS.
//
public uint SegGs;
public uint SegFs;
public uint SegEs;
public uint SegDs;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_INTEGER.
//
public uint edi;
public uint esi;
public uint ebx;
public uint edx;
public uint ecx;
public uint eax;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_CONTROL.
//
/// <summary>
/// Base/Frame pointer
/// </summary>
public uint ebp;
/// <summary>
/// Instruction pointer
/// </summary>
public uint eip;
public uint segCs; // MUST BE SANITIZED
public Extendedx86ContextFlags eFlags; // MUST BE SANITIZED
/// <summary>
/// Stack pointer
/// </summary>
public uint esp;
public uint segSs;
//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAXIMUM_SUPPORTED_EXTENSION)]
public byte[] ExtendedRegisters;
}
public static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT_x86 lpContext);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT_x86 lpContext);
}
}

View File

@ -0,0 +1,39 @@
// 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);
}
}
}

View File

@ -0,0 +1,5 @@
namespace VsChromium.Core.Win32 {
public static class Constants {
public const uint INFINITE = 0xFFFFFFFF;
}
}

View File

@ -0,0 +1,6 @@
namespace VsChromium.Core.Win32.Debugging {
public enum CONTINUE_STATUS : uint {
DBG_CONTINUE = 0x00010002,
DBG_EXCEPTION_NOT_HANDLED = 0x80010001,
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_PROCESS_DEBUG_INFO {
public IntPtr hFile;
public IntPtr hProcess;
public IntPtr hThread;
public IntPtr lpBaseOfImage;
public uint dwDebugInfoFileOffset;
public uint nDebugInfoSize;
public IntPtr lpThreadLocalBase;
public PTHREAD_START_ROUTINE lpStartAddress;
public IntPtr lpImageName;
public ushort fUnicode;
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_THREAD_DEBUG_INFO {
public IntPtr hThread;
public IntPtr lpThreadLocalBase;
public PTHREAD_START_ROUTINE lpStartAddress;
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct DEBUG_EVENT {
public DEBUG_EVENT_CODE dwDebugEventCode;
public int dwProcessId;
public int dwThreadId;
// Note: We need 164 bytes because:
// * On x86, offset is 12 and size is 84
// * On x64, offset is 16 and size is 160 (so we skip first 4 bytes).
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 164, ArraySubType = UnmanagedType.U1)]
public byte[] debugInfo;
public EXCEPTION_DEBUG_INFO Exception {
get { return GetDebugInfo<EXCEPTION_DEBUG_INFO>(); }
}
public CREATE_THREAD_DEBUG_INFO CreateThread {
get { return GetDebugInfo<CREATE_THREAD_DEBUG_INFO>(); }
}
public CREATE_PROCESS_DEBUG_INFO CreateProcessInfo {
get { return GetDebugInfo<CREATE_PROCESS_DEBUG_INFO>(); }
}
public EXIT_THREAD_DEBUG_INFO ExitThread {
get { return GetDebugInfo<EXIT_THREAD_DEBUG_INFO>(); }
}
public EXIT_PROCESS_DEBUG_INFO ExitProcess {
get { return GetDebugInfo<EXIT_PROCESS_DEBUG_INFO>(); }
}
public LOAD_DLL_DEBUG_INFO LoadDll {
get { return GetDebugInfo<LOAD_DLL_DEBUG_INFO>(); }
}
public UNLOAD_DLL_DEBUG_INFO UnloadDll {
get { return GetDebugInfo<UNLOAD_DLL_DEBUG_INFO>(); }
}
public OUTPUT_DEBUG_STRING_INFO DebugString {
get { return GetDebugInfo<OUTPUT_DEBUG_STRING_INFO>(); }
}
public RIP_INFO RipInfo {
get { return GetDebugInfo<RIP_INFO>(); }
}
private T GetDebugInfo<T>() where T : struct {
var structSize = Marshal.SizeOf(typeof(T));
var pointer = Marshal.AllocHGlobal(structSize);
try {
// See note above: offset of union is 4 on x64.
int offset = IntPtr.Size == 4 ? 0 : 4;
Marshal.Copy(debugInfo, offset, pointer, structSize);
var result = Marshal.PtrToStructure(pointer, typeof(T));
return (T)result;
}
finally {
Marshal.FreeHGlobal(pointer);
}
}
}
}

View File

@ -0,0 +1,13 @@
namespace VsChromium.Core.Win32.Debugging {
public enum DEBUG_EVENT_CODE : uint {
EXCEPTION_DEBUG_EVENT = 1,
CREATE_THREAD_DEBUG_EVENT = 2,
CREATE_PROCESS_DEBUG_EVENT = 3,
EXIT_THREAD_DEBUG_EVENT = 4,
EXIT_PROCESS_DEBUG_EVENT = 5,
LOAD_DLL_DEBUG_EVENT = 6,
UNLOAD_DLL_DEBUG_EVENT = 7,
OUTPUT_DEBUG_STRING_EVENT = 8,
RIP_EVENT = 9,
}
}

View File

@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_DEBUG_INFO {
public EXCEPTION_RECORD ExceptionRecord;
public uint dwFirstChance;
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging
{
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_RECORD
{
public UInt32 ExceptionCode;
public UInt32 ExceptionFlags;
public IntPtr ExceptionRecord;
public IntPtr ExceptionAddress;
public UInt32 NumberParameters;
#if X64
public UInt32 __unusedAlignment;
#endif
#if X64
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U8)]
public UInt64[] ExceptionInformation;
#else
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U4)]
public uint[] ExceptionInformation;
#endif
}
}

View File

@ -0,0 +1,8 @@
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_PROCESS_DEBUG_INFO {
public uint dwExitCode;
}
}

View File

@ -0,0 +1,8 @@
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_THREAD_DEBUG_INFO {
public uint dwExitCode;
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct LOAD_DLL_DEBUG_INFO {
public IntPtr hFile;
public IntPtr lpBaseOfDll;
public uint dwDebugInfoFileOffset;
public uint nDebugInfoSize;
public IntPtr lpImageName;
public ushort fUnicode;
}
}

View File

@ -0,0 +1,25 @@
// Copyright 2013 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.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
public static class NativeMethods {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DebugActiveProcess(int processId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DebugActiveProcessStop(int processId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WaitForDebugEvent(out DEBUG_EVENT debugEvent, uint timeout);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ContinueDebugEvent(int processId, int threadId, CONTINUE_STATUS continuteStatus);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DebugSetProcessKillOnExit([In] bool flag);
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct OUTPUT_DEBUG_STRING_INFO {
/// <summary>
/// The debugging string in the calling process's address space. The
/// debugger can use the ReadProcessMemory function to retrieve the value of
/// the string.
/// </summary>
public IntPtr lpDebugStringData;
/// <summary>
/// The format of the debugging string. If this member is zero, the debugging
/// string is ANSI; if it is nonzero, the string is Unicode.
/// </summary>
public ushort fUnicode;
/// <summary>
/// The size of the debugging string, in characters. The length includes the
/// string's terminating null character.
/// </summary>
public ushort nDebugStringLength;
}
}

View File

@ -0,0 +1,9 @@
// Copyright 2013 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;
namespace VsChromium.Core.Win32.Debugging {
public delegate uint PTHREAD_START_ROUTINE(IntPtr lpThreadParameter);
}

View File

@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct RIP_INFO {
public uint dwError;
public uint dwType;
}
}

View File

@ -0,0 +1,9 @@
using System;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Debugging {
[StructLayout(LayoutKind.Sequential)]
public struct UNLOAD_DLL_DEBUG_INFO {
public IntPtr lpBaseOfDll;
}
}

View File

@ -0,0 +1,6 @@
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);
}
}

View File

@ -0,0 +1,34 @@
// Copyright 2013 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.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace VsChromium.Core.Win32.Handles
{
static class NativeMethods
{
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetStdHandle(int whichHandle);
[DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern bool DuplicateHandle(
HandleRef hSourceProcessHandle,
SafeHandle hSourceHandle,
HandleRef hTargetProcess,
out SafeFileHandle targetHandle,
int dwDesiredAccess,
bool bInheritHandle,
int dwOptions);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern UInt32 WaitForSingleObject(SafeHandle hHandle, UInt32 dwMilliseconds);
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2013 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.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Interop
{
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace LowLevelDesign.Win32.Jobs
{
[StructLayout(LayoutKind.Sequential)]
public struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
}
}

View File

@ -0,0 +1,13 @@
namespace LowLevelDesign.Win32.Jobs
{
public enum JOBOBJECTINFOCLASS
{
AssociateCompletionPortInformation = 7,
BasicLimitInformation = 2,
BasicUIRestrictions = 4,
EndOfJobTimeInformation = 6,
ExtendedLimitInformation = 9,
SecurityLimitInformation = 5,
GroupInformation = 11
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Runtime.InteropServices;
namespace LowLevelDesign.Win32.Jobs
{
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT
{
public IntPtr CompletionKey;
public IntPtr CompletionPort;
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Runtime.InteropServices;
namespace LowLevelDesign.Win32.Jobs
{
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public JobInformationLimitFlags LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public Int64 Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace LowLevelDesign.Win32.Jobs
{
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
}

View File

@ -0,0 +1,24 @@
using System;
namespace LowLevelDesign.Win32.Jobs
{
[Flags]
public enum JobInformationLimitFlags
{
JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008,
JOB_OBJECT_LIMIT_AFFINITY = 0x00000010,
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800,
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400,
JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200,
JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004,
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000,
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040,
JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020,
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100,
JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002,
JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080,
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000,
JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001
}
}

View File

@ -0,0 +1,16 @@
namespace LowLevelDesign.Win32.Jobs
{
public enum JobMsgInfoMessages
{
JOB_OBJECT_MSG_END_OF_JOB_TIME = 1,
JOB_OBJECT_MSG_END_OF_PROCESS_TIME = 2,
JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT = 3,
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4,
JOB_OBJECT_MSG_NEW_PROCESS = 6,
JOB_OBJECT_MSG_EXIT_PROCESS = 7,
JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8,
JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT = 9,
JOB_OBJECT_MSG_JOB_MEMORY_LIMIT = 10
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Runtime.InteropServices;
using VsChromium.Core.Win32.Interop;
namespace LowLevelDesign.Win32.Jobs
{
internal static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateJobObject([In]SecurityAttributes lpJobAttributes, string lpName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool TerminateJobObject(IntPtr hJob, uint uExitCode);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass,
ref JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass,
ref JOBOBJECT_ASSOCIATE_COMPLETION_PORT lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort,
IntPtr CompletionKey, uint NumberOfConcurrentThreads);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetQueuedCompletionStatus(IntPtr CompletionPort, out uint lpNumberOfBytes,
out IntPtr lpCompletionKey, out IntPtr lpOverlapped, uint dwMilliseconds);
}
}

View File

@ -0,0 +1,23 @@
// Copyright 2013 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.ComponentModel;
using System.Runtime.InteropServices;
namespace VsChromium.Core.Win32 {
public class LastWin32ErrorException : Win32Exception {
public LastWin32ErrorException()
: base(Marshal.GetLastWin32Error()) {
}
public LastWin32ErrorException(string message)
: this(Marshal.GetLastWin32Error(), message) {
}
public LastWin32ErrorException(int errorCode)
: base(errorCode) {
}
public LastWin32ErrorException(int errorCode, string message)
: base(errorCode, string.Format("{0}: {1}", message, new Win32Exception(errorCode).Message)) {
}
}
}

View File

@ -0,0 +1,9 @@
// Copyright 2013 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.
namespace VsChromium.Core.Win32 {
public static class NtStatus {
public const int Success = 0;
}
}

View File

@ -0,0 +1,64 @@
// Copyright 2013 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;
namespace VsChromium.Core.Win32.Processes {
// The target architecture of a given executable image. The various values correspond
// to the magic numbers defined by the PE Executable Image File Format.
// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
public enum MachineType : ushort {
Unknown = 0x0,
X64 = 0x8664,
X86 = 0x14c,
Ia64 = 0x200
}
// A flag indicating the format of the path string that Windows returns from a call to
// QueryFullProcessImageName().
public enum ProcessQueryImageNameMode : uint {
Win32 = 0,
NativeSystemFormat = 1
}
// Flags indicating the level of permission requested when opening a handle to an external
// process. Used by OpenProcess().
[Flags]
public enum ProcessAccessFlags : uint {
None = 0x0,
All = 0x001F0FFF,
VmOperation = 0x00000008,
VmRead = 0x00000010,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000
}
// Determines the amount of information requested (and hence the type of structure returned)
// by a call to NtQueryInformationProcess.
public enum ProcessInfoClass : int {
BasicInformation = 0
};
[Flags]
public enum SHGFI : uint {
Icon = 0x000000100,
DisplayName = 0x000000200,
TypeName = 0x000000400,
Attributes = 0x000000800,
IconLocation = 0x000001000,
ExeType = 0x000002000,
SysIconIndex = 0x000004000,
LinkOverlay = 0x000008000,
Selected = 0x000010000,
Attr_Specified = 0x000020000,
LargeIcon = 0x000000000,
SmallIcon = 0x000000001,
OpenIcon = 0x000000002,
ShellIconSize = 0x000000004,
PIDL = 0x000000008,
UseFileAttributes = 0x000000010,
AddOverlays = 0x000000020,
OverlayIndex = 0x000000040,
}
}

View File

@ -0,0 +1,91 @@
// Copyright 2013 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.Runtime.InteropServices;
using System.Text;
using VsChromium.Core.Win32.Interop;
namespace VsChromium.Core.Win32.Processes
{
static class NativeMethods
{
[DllImport("shell32.dll", SetLastError = true)]
public static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine,
out int pNumArgs);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CreateProcess(
[MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName,
StringBuilder lpCommandLine,
SecurityAttributes lpProcessAttributes,
SecurityAttributes lpThreadAttributes,
bool bInheritHandles,
ProcessCreationFlags dwCreationFlags,
StringBuilder lpEnvironment,
[MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory,
STARTUPINFO lpStartupInfo,
[In, Out]
PROCESS_INFORMATION lpProcessInformation);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtReadVirtualMemory(
SafeProcessHandle hProcess,
IntPtr baseAddress,
[Out] byte[] buffer,
uint size,
out uint lpNumberOfBytesRead);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtWow64ReadVirtualMemory64(
SafeProcessHandle hProcess,
ulong baseAddress,
IntPtr buffer,
ulong bufferSize,
out ulong lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeProcessHandle OpenProcess(
[MarshalAs(UnmanagedType.U4)] ProcessAccessFlags dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
public static extern uint QueryFullProcessImageName(
SafeProcessHandle hProcess,
[MarshalAs(UnmanagedType.U4)] ProcessQueryImageNameMode flags,
[Out] StringBuilder lpImageName, ref int size);
[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);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtQueryInformationProcess(SafeProcessHandle hProcess, ProcessInfoClass pic, ref ProcessBasicInformation pbi, int cb, out int pSize);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtWow64QueryInformationProcess64(SafeProcessHandle hProcess, ProcessInfoClass pic, ref ProcessBasicInformationWow64 pbi, int cb, out int pSize);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetProcessAffinityMask(SafeProcessHandle hProcess, out long lpProcessAffinityMask,
out long lpSystemAffinityMask);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int ResumeThread(IntPtr hThread);
// x1nix: added
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SuspendThread(IntPtr hThread);
// x1nix: added
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool TerminateProcess(SafeProcessHandle hProcess, uint uExitCode);
}
}

View File

@ -0,0 +1,125 @@
// Copyright 2013 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.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Processes {
// In general, for all structures below which contains a pointer (represented here by IntPtr),
// the pointers refer to memory in the address space of the process from which the original
// structure was read. While this seems obvious, it means we cannot provide an elegant
// interface to the various fields in the structure due to the de-reference requiring a
// handle to the target process. Instead, that functionality needs to be provided at a
// higher level.
//
// Additionally, since we usually explicitly define the fields that we're interested in along
// with their respective offsets, we frequently specify the exact size of the native structure.
// Win32 RTL_USER_PROCESS_PARAMETERS structure.
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct RtlUserProcessParameters {
private uint maximumLength;
private uint length;
private uint flags;
private uint debugFlags;
private IntPtr consoleHandle;
private uint consoleFlags;
private IntPtr stdInputHandle;
private IntPtr stdOutputHandle;
private IntPtr stdErrorHandle;
private UnicodeString currentDirectoryPath;
private IntPtr currentDirectoryHandle;
private UnicodeString dllPath;
private UnicodeString imagePathName;
private UnicodeString commandLine;
public UnicodeString CommandLine { get { return commandLine; } }
};
// Win32 RTL_USER_PROCESS_PARAMETERS structure.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RtlUserProcessParametersWow64 {
private uint maximumLength;
private uint length;
private uint flags;
private uint debugFlags;
private ulong consoleHandle;
private uint consoleFlags;
private uint padding;
private ulong stdInputHandle;
private ulong stdOutputHandle;
private ulong stdErrorHandle;
private UnicodeStringWow64 currentDirectoryPath;
private ulong currentDirectoryHandle;
private UnicodeStringWow64 dllPath;
private UnicodeStringWow64 imagePathName;
private UnicodeStringWow64 commandLine;
public UnicodeStringWow64 CommandLine { get { return commandLine; } }
};
// Win32 PEB structure. Represents the process environment block of a process.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Peb {
private byte inheritedAddressSpace;
private byte readImageFileExecutionOptions;
private byte isBeingDebugged;
private byte reserved;
private IntPtr mutant;
private IntPtr imageBaseAddress;
private IntPtr loaderData;
private IntPtr processParameters;
public bool IsBeingDebugged { get { return !(isBeingDebugged == 0); } }
public IntPtr ProcessParameters { get { return processParameters; } }
};
// Win32 PEB structure. Represents the process environment block of a process.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PebWow64 {
private byte inheritedAddressSpace;
private byte readImageFileExecutionOptions;
private byte isBeingDebugged;
private byte reserved;
private uint padding;
private ulong mutant;
private ulong imageBaseAddress;
private ulong loaderData;
private ulong processParameters;
public bool IsBeingDebugged { get { return !(isBeingDebugged == 0); } }
public ulong ProcessParameters { get { return processParameters; } }
};
// Win32 PROCESS_BASIC_INFORMATION. Contains a pointer to the PEB, and various other
// information about a process.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ProcessBasicInformation {
private IntPtr reserved;
private IntPtr pebBaseAddress;
private IntPtr reserved2;
private IntPtr reserved3;
private UIntPtr uniqueProcessId;
private IntPtr parentProcessId;
public IntPtr PebBaseAddress { get { return pebBaseAddress; } }
public UIntPtr UniqueProcessId { get { return uniqueProcessId; } }
public IntPtr ParentProcessId { get { return parentProcessId; } }
}
// Win32 PROCESS_BASIC_INFORMATION. Contains a pointer to the PEB, and various other
// information about a process.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ProcessBasicInformationWow64 {
private ulong reserved;
private ulong pebBaseAddress;
private ulong reserved2;
private ulong reserved3;
private ulong uniqueProcessId;
private ulong parentProcessId;
public ulong PebBaseAddress { get { return pebBaseAddress; } }
public ulong UniqueProcessId { get { return uniqueProcessId; } }
public ulong ParentProcessId { get { return parentProcessId; } }
}
}

View File

@ -0,0 +1,22 @@
// Copyright 2013 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.Runtime.InteropServices;
namespace VsChromium.Core.Win32.Processes {
[StructLayout(LayoutKind.Sequential)]
public class PROCESS_INFORMATION {
/// <summary>
/// Handle to the created process. The caller *must* call CloseHandle to avoid leaks.
/// </summary>
public IntPtr hProcess;
/// <summary>
/// Handle to the created process main thread. The caller *must* call CloseHandle to avoid leaks.
/// </summary>
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
}

View File

@ -0,0 +1,50 @@
// Copyright 2013 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;
namespace VsChromium.Core.Win32.Processes {
[Flags]
public enum ProcessCreationFlags : int {
/// <summary>
/// The calling thread starts and debugs the new process and all child
/// processes created by the new process. It can receive all related debug
/// events using the WaitForDebugEvent function. A process that uses
/// DEBUG_PROCESS becomes the root of a debugging chain. This continues
/// until another process in the chain is created with DEBUG_PROCESS. If
/// this flag is combined with DEBUG_ONLY_THIS_PROCESS, the caller debugs
/// only the new process, not any child processes.
/// </summary>
DEBUG_PROCESS = 0x00000001,
/// <summary>
/// The calling thread starts and debugs the new process. It can receive all
/// related debug events using the WaitForDebugEvent function.
/// </summary>
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
/// <summary>
/// The child processes of a process associated with a job are not
/// associated with the job. If the calling process is not associated with a
/// job, this constant has no effect. If the calling process is associated
/// with a job, the job must set the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit.
/// </summary>
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
/// <summary>
/// The process is a console application that is being run without a console
/// window. Therefore, the console handle for the application is not set.
/// This flag is ignored if the application is not a console application, or
/// if it is used with either CREATE_NEW_CONSOLE or DETACHED_PROCESS.
/// </summary>
CREATE_NO_WINDOW = 0x08000000,
/// <summary>
/// The primary thread of the new process is created in a suspended state,
/// and does not run until the ResumeThread function is called.
CREATE_SUSPENDED = 0x00000004,
/// <summary>
/// The new process has a new console, instead of inheriting its parent's console (the default).
///
/// This flag cannot be used with DETACHED_PROCESS.
/// </summary>
CREATE_NEW_CONSOLE = 0x00000010
}
}

View File

@ -0,0 +1,27 @@
// Copyright 2013 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 Microsoft.Win32.SafeHandles;
namespace VsChromium.Core.Win32.Processes {
public sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid {
public SafeProcessHandle()
: base(true) {
}
public SafeProcessHandle(IntPtr handle)
: base(true) {
base.SetHandle(handle);
}
public void InitialSetHandle(IntPtr handlePtr) {
handle = handlePtr;
}
protected override bool ReleaseHandle() {
return Handles.NativeMethods.CloseHandle(handle);
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright 2013 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 Microsoft.Win32.SafeHandles;
namespace VsChromium.Core.Win32.Processes {
public sealed class SafeThreadHandle : SafeHandleZeroOrMinusOneIsInvalid {
public SafeThreadHandle()
: base(true) {
}
public SafeThreadHandle(IntPtr handle)
: base(true) {
base.SetHandle(handle);
}
public void InitialSetHandle(IntPtr h) {
base.SetHandle(h);
}
protected override bool ReleaseHandle() {
return Handles.NativeMethods.CloseHandle(handle);
}
}
}

View File

@ -0,0 +1,50 @@
// Copyright 2013 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.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace VsChromium.Core.Win32.Processes {
[StructLayout(LayoutKind.Sequential)]
public class STARTUPINFO : IDisposable {
public int cb;
public IntPtr lpReserved = IntPtr.Zero;
public IntPtr lpDesktop = IntPtr.Zero;
public IntPtr lpTitle = IntPtr.Zero;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2 = IntPtr.Zero;
public SafeFileHandle hStdInput = new SafeFileHandle(IntPtr.Zero, false);
public SafeFileHandle hStdOutput = new SafeFileHandle(IntPtr.Zero, false);
public SafeFileHandle hStdError = new SafeFileHandle(IntPtr.Zero, false);
public STARTUPINFO() {
cb = Marshal.SizeOf(this);
}
public void Dispose() {
if (hStdInput != null && !hStdInput.IsInvalid) {
hStdInput.Close();
hStdInput = null;
}
if (hStdOutput != null && !hStdOutput.IsInvalid) {
hStdOutput.Close();
hStdOutput = null;
}
if (hStdError != null && !hStdError.IsInvalid) {
hStdError.Close();
hStdError = null;
}
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright 2013 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.Runtime.InteropServices;
namespace VsChromium.Core.Win32 {
// Win32 UNICODE_STRING structure.
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct UnicodeString {
// The length in bytes of the string pointed to by buffer, not including the null-terminator.
private ushort length;
// The total allocated size in memory pointed to by buffer.
private ushort maximumLength;
// A pointer to the buffer containing the string data.
private IntPtr buffer;
public ushort Length { get { return length; } }
public ushort MaximumLength { get { return maximumLength; } }
public IntPtr Buffer { get { return buffer; } }
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UnicodeStringWow64 {
// The length in bytes of the string pointed to by buffer, not including the null-terminator.
private ushort length;
// The total allocated size in memory pointed to by buffer.
private ushort maximumLength;
// 4 bytes of padding.
private uint padding;
// A 64-bit pointer to the buffer containing the string data.
private ulong buffer;
public ushort Length { get { return length; } }
public ushort MaximumLength { get { return maximumLength; } }
public ulong Buffer { get { return buffer; } }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Runtime.InteropServices;
namespace LowLevelDesign.Win32.Windows
{
public static class NativeMethods
{
public const int SW_HIDE = 0;
public const int SW_SHOW = 5;
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// x1nix: added
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetFinalPathNameByHandleW(IntPtr hFile, IntPtr lpszFilePath, uint cchFilePath = 0u, uint dwFlags = 0u);
}
}

View File

@ -0,0 +1,27 @@
Copyright 2013 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.