Fixed structure alignment bug (#50) in Debug Api calls.

pull/60/head
David Hall 2019-05-21 23:19:07 -04:00
parent 729063333c
commit 9e25dfe47b
5 changed files with 400 additions and 297 deletions

View File

@ -1,5 +1,7 @@
using System;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;
namespace Vanara.PInvoke
{
@ -310,6 +312,9 @@ namespace Vanara.PInvoke
/// </summary>
public uint dwProcessId;
// This is used to ensure the union structure EXCEPTION_INFO falls at offset 12 in 32-bit and 16 on 64-bit
private IntPtr padding3264hack;
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>
@ -317,7 +322,7 @@ namespace Vanara.PInvoke
/// per-thread structure. These values are not necessarily small integers that can be used as table indices.
/// </para>
/// </summary>
public uint dwThreadId;
public uint dwThreadId { get => (uint)padding3264hack.ToInt32(); set => padding3264hack = (IntPtr)dwThreadId; }
/// <summary>
/// Any additional information relating to the debugging event. This union takes on the type and value appropriate to the type of
@ -342,328 +347,340 @@ namespace Vanara.PInvoke
/// </summary>
[FieldOffset(0)]
public CREATE_THREAD_DEBUG_INFO CreateThread;
/// <summary>
/// If the dwDebugEventCode is CREATE_PROCESS_DEBUG_EVENT (3), u.CreateProcessInfo specifies an CREATE_PROCESS_DEBUG_INFO structure.
/// </summary>
[FieldOffset(0)]
public CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
/// <summary>
/// If the dwDebugEventCode is EXIT_THREAD_DEBUG_EVENT (4), u.ExitThread specifies an EXIT_THREAD_DEBUG_INFO structure.
/// </summary>
[FieldOffset(0)]
public EXIT_THREAD_DEBUG_INFO ExitThread;
/// <summary>
/// If the dwDebugEventCode is EXIT_PROCESS_DEBUG_EVENT (5), u.ExitProcess specifies an EXIT_PROCESS_DEBUG_INFO structure.
/// </summary>
[FieldOffset(0)]
public EXIT_PROCESS_DEBUG_INFO ExitProcess;
/// <summary>If the dwDebugEventCode is LOAD_DLL_DEBUG_EVENT (6), u.LoadDll specifies an LOAD_DLL_DEBUG_INFO structure.</summary>
[FieldOffset(0)]
public LOAD_DLL_DEBUG_INFO LoadDll;
/// <summary>If the dwDebugEventCode is UNLOAD_DLL_DEBUG_EVENT (7), u.UnloadDll specifies an UNLOAD_DLL_DEBUG_INFO structure.</summary>
[FieldOffset(0)]
public UNLOAD_DLL_DEBUG_INFO UnloadDll;
/// <summary>
/// If the dwDebugEventCode is OUTPUT_DEBUG_STRING_EVENT (8), u.DebugString specifies an OUTPUT_DEBUG_STRING_INFO structure.
/// </summary>
[FieldOffset(0)]
public OUTPUT_DEBUG_STRING_INFO DebugString;
/// <summary>If the dwDebugEventCode is RIP_EVENT (9), u.RipInfo specifies an RIP_INFO structure.</summary>
[FieldOffset(0)]
public RIP_INFO RipInfo;
/// <summary>Contains exception information that can be used by a debugger.</summary>
// typedef struct _EXCEPTION_DEBUG_INFO { EXCEPTION_RECORD ExceptionRecord; DWORD dwFirstChance;} EXCEPTION_DEBUG_INFO,
// *LPEXCEPTION_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679326(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679326")]
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_DEBUG_INFO
{
/// <summary>
/// An <c>EXCEPTION_RECORD</c> structure with information specific to the exception. This includes the exception code,
/// flags, address, a pointer to a related exception, extra parameters, and so on.
/// </summary>
public EXCEPTION_RECORD ExceptionRecord;
/// <summary>
/// A value that indicates whether the debugger has previously encountered the exception specified by the
/// <c>ExceptionRecord</c> member. If the <c>dwFirstChance</c> member is nonzero, this is the first time the debugger has
/// encountered the exception. Debuggers typically handle breakpoint and single-step exceptions when they are first
/// encountered. If this member is zero, the debugger has previously encountered the exception. This occurs only if,
/// during the search for structured exception handlers, either no handler was found or the exception was continued.
/// </summary>
public uint dwFirstChance;
}
/// <summary>Contains thread-creation information that can be used by a debugger.</summary>
// typedef struct _CREATE_THREAD_DEBUG_INFO { HANDLE hThread; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE
// lpStartAddress;} CREATE_THREAD_DEBUG_INFO,
// *LPCREATE_THREAD_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679287(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679287")]
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_THREAD_DEBUG_INFO
{
/// <summary>
/// A handle to the thread whose creation caused the debugging event. If this member is <c>NULL</c>, the handle is not
/// valid. Otherwise, the debugger has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the
/// thread, allowing the debugger to read from and write to the registers of the thread and control execution of the thread.
/// </summary>
public HTHREAD hThread;
/// <summary>
/// A pointer to a block of data. At offset 0x2C into this block is another pointer, called ThreadLocalStoragePointer,
/// that points to an array of per-module thread local storage blocks. This gives a debugger access to per-thread data in
/// the threads of the process being debugged using the same algorithms that a compiler would use.
/// </summary>
public IntPtr lpThreadLocalBase;
/// <summary>
/// A pointer to the starting address of the thread. This value may only be an approximation of the thread's starting
/// address, because any application with appropriate access to the thread can change the thread's context by using the
/// <c>SetThreadContext</c> function.
/// </summary>
public PTHREAD_START_ROUTINE lpStartAddress;
}
/// <summary>Contains process creation information that can be used by a debugger.</summary>
// typedef struct _CREATE_PROCESS_DEBUG_INFO { HANDLE hFile; HANDLE hProcess; HANDLE hThread; LPVOID lpBaseOfImage; DWORD
// dwDebugInfoFileOffset; DWORD nDebugInfoSize; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE lpStartAddress; LPVOID
// lpImageName; WORD fUnicode;} CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
[PInvokeData("WinBase.h", MSDNShortId = "ms679286")]
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_PROCESS_DEBUG_INFO
{
/// <summary>
/// <para>
/// A handle to the process's image file. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the debugger
/// can use the member to read from and write to the image file.
/// </para>
/// <para>When the debugger is finished with this file, it should close the handle using the <c>CloseHandle</c> function.</para>
/// </summary>
public HFILE hFile;
/// <summary>
/// A handle to the process. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the debugger can use the
/// member to read from and write to the process's memory.
/// </summary>
public HPROCESS hProcess;
/// <summary>
/// A handle to the initial thread of the process identified by the <c>hProcess</c> member. If <c>hThread</c> param is
/// <c>NULL</c>, the handle is not valid. Otherwise, the debugger has <c>THREAD_GET_CONTEXT</c>,
/// <c>THREAD_SET_CONTEXT</c>, and <c>THREAD_SUSPEND_RESUME</c> access to the thread, allowing the debugger to read from
/// and write to the registers of the thread and to control execution of the thread.
/// </summary>
public HTHREAD hThread;
/// <summary>The base address of the executable image that the process is running.</summary>
public IntPtr lpBaseOfImage;
/// <summary>The offset to the debugging information in the file identified by the <c>hFile</c> member.</summary>
public uint dwDebugInfoFileOffset;
/// <summary>
/// The size of the debugging information in the file, in bytes. If this value is zero, there is no debugging information.
/// </summary>
public uint nDebugInfoSize;
/// <summary>
/// A pointer to a block of data. At offset 0x2C into this block is another pointer, called , that points to an array of
/// per-module thread local storage blocks. This gives a debugger access to per-thread data in the threads of the process
/// being debugged using the same algorithms that a compiler would use.
/// </summary>
public IntPtr lpThreadLocalBase;
/// <summary>
/// A pointer to the starting address of the thread. This value may only be an approximation of the thread's starting
/// address, because any application with appropriate access to the thread can change the thread's context by using the
/// <c>SetThreadContext</c> function.
/// </summary>
public PTHREAD_START_ROUTINE lpStartAddress;
/// <summary>
/// <para>
/// A pointer to the file name associated with the <c>hFile</c> member. This parameter may be <c>NULL</c>, or it may
/// contain the address of a string pointer in the address space of the process being debugged. That address may, in
/// turn, either be <c>NULL</c> or point to the actual filename. If <c>fUnicode</c> is a nonzero value, the name string
/// is Unicode; otherwise, it is ANSI.
/// </para>
/// <para>
/// This member is strictly optional. Debuggers must be prepared to handle the case where <c>lpImageName</c> is
/// <c>NULL</c> or * <c>lpImageName</c> (in the address space of the process being debugged) is <c>NULL</c>.
/// Specifically, the system does not provide an image name for a create process event, and will not likely pass an image
/// name for the first DLL event. The system also does not provide this information in the case of debug events that
/// originate from a call to the <c>DebugActiveProcess</c> function.
/// </para>
/// </summary>
public IntPtr lpImageName;
/// <summary>
/// A value that indicates whether a file name specified by the <c>lpImageName</c> member is Unicode or ANSI. A nonzero
/// value indicates Unicode; zero indicates ANSI.
/// </summary>
public ushort fUnicode;
}
/// <summary>Contains the exit code for a terminating process.</summary>
// typedef struct _EXIT_PROCESS_DEBUG_INFO { DWORD dwExitCode;} EXIT_PROCESS_DEBUG_INFO, *LPEXIT_PROCESS_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679334(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679334")]
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_PROCESS_DEBUG_INFO
{
/// <summary>The exit code for the process.</summary>
public uint dwExitCode;
}
/// <summary>Contains the exit code for a terminating thread.</summary>
// typedef struct _EXIT_THREAD_DEBUG_INFO { DWORD dwExitCode;} EXIT_THREAD_DEBUG_INFO, *LPEXIT_THREAD_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679335(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679335")]
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_THREAD_DEBUG_INFO
{
/// <summary>The exit code for the thread.</summary>
public uint dwExitCode;
}
/// <summary>Contains information about a dynamic-link library (DLL) that has just been loaded.</summary>
// typedef struct _LOAD_DLL_DEBUG_INFO { HANDLE hFile; LPVOID lpBaseOfDll; DWORD dwDebugInfoFileOffset; DWORD nDebugInfoSize;
// LPVOID lpImageName; WORD fUnicode;} LOAD_DLL_DEBUG_INFO, *LPLOAD_DLL_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680351(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680351")]
[StructLayout(LayoutKind.Sequential)]
public struct LOAD_DLL_DEBUG_INFO
{
/// <summary>
/// <para>
/// A handle to the loaded DLL. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the member is opened
/// for reading and read-sharing in the context of the debugger.
/// </para>
/// <para>When the debugger is finished with this file, it should close the handle using the <c>CloseHandle</c> function.</para>
/// </summary>
public HFILE hFile;
/// <summary>A pointer to the base address of the DLL in the address space of the process loading the DLL.</summary>
public IntPtr lpBaseOfDll;
/// <summary>
/// The offset to the debugging information in the file identified by the <c>hFile</c> member, in bytes. The system
/// expects the debugging information to be in CodeView 4.0 format. This format is currently a derivative of Common
/// Object File Format (COFF).
/// </summary>
public uint dwDebugInfoFileOffset;
/// <summary>
/// The size of the debugging information in the file, in bytes. If this member is zero, there is no debugging information.
/// </summary>
public uint nDebugInfoSize;
/// <summary>
/// <para>
/// A pointer to the file name associated with <c>hFile</c>. This member may be <c>NULL</c>, or it may contain the
/// address of a string pointer in the address space of the process being debugged. That address may, in turn, either be
/// <c>NULL</c> or point to the actual filename. If <c>fUnicode</c> is a nonzero value, the name string is Unicode;
/// otherwise, it is ANSI.
/// </para>
/// <para>
/// This member is strictly optional. Debuggers must be prepared to handle the case where <c>lpImageName</c> is
/// <c>NULL</c> or * <c>lpImageName</c> (in the address space of the process being debugged) is <c>NULL</c>.
/// Specifically, the system will never provide an image name for a create process event, and it will not likely pass an
/// image name for the first DLL event. The system will also never provide this information in the case of debugging
/// events that originate from a call to the <c>DebugActiveProcess</c> function.
/// </para>
/// </summary>
public IntPtr lpImageName;
/// <summary>
/// A value that indicates whether a filename specified by <c>lpImageName</c> is Unicode or ANSI. A nonzero value for
/// this member indicates Unicode; zero indicates ANSI.
/// </summary>
public ushort fUnicode;
}
/// <summary>Contains information about a dynamic-link library (DLL) that has just been unloaded.</summary>
// typedef struct _UNLOAD_DLL_DEBUG_INFO { LPVOID lpBaseOfDll;} UNLOAD_DLL_DEBUG_INFO, *LPUNLOAD_DLL_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms681403(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms681403")]
[StructLayout(LayoutKind.Sequential)]
public struct UNLOAD_DLL_DEBUG_INFO
{
/// <summary>A pointer to the base address of the DLL in the address space of the process unloading the DLL.</summary>
public IntPtr lpBaseOfDll;
}
/// <summary>Contains the address, format, and length, in bytes, of a debugging string.</summary>
// typedef struct _OUTPUT_DEBUG_STRING_INFO { LPSTR lpDebugStringData; WORD fUnicode; WORD nDebugStringLength;} OUTPUT_DEBUG_STRING_INFO,
// *LPOUTPUT_DEBUG_STRING_INFO;// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680545(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680545")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct OUTPUT_DEBUG_STRING_INFO
{
/// <summary>
/// The debugging string in the calling process's address space. The debugger can use the <c>ReadProcessMemory</c>
/// function to retrieve the value of the string.
/// </summary>
public string 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;
}
/// <summary>Contains the error that caused the RIP debug event.</summary>
// typedef struct _RIP_INFO { DWORD dwError; DWORD dwType;} RIP_INFO, *LPRIP_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680587(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680587")]
[StructLayout(LayoutKind.Sequential)]
public struct RIP_INFO
{
/// <summary>The error that caused the RIP debug event. For more information, see Error Handling.</summary>
public uint dwError;
/// <summary>
/// <para>
/// Any additional information about the type of error that caused the RIP debug event. This member can be one of the
/// following values.
/// </para>
/// <para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SLE_ERROR = 0x00000001</term>
/// <term>Indicates that invalid data was passed to the function that failed. This caused the application to fail.</term>
/// </item>
/// <item>
/// <term>SLE_MINORERROR = 0x00000002</term>
/// <term>
/// Indicates that invalid data was passed to the function, but the error probably will not cause the application to fail.
/// </term>
/// </item>
/// <item>
/// <term>SLE_WARNING = 0x00000003</term>
/// <term>Indicates that potentially invalid data was passed to the function, but the function completed processing.</term>
/// </item>
/// <item>
/// <term>0</term>
/// <term>Indicates that only dwError was set.</term>
/// </item>
/// </list>
/// </para>
/// </summary>
public uint dwType;
}
}
/// <summary>Contains exception information that can be used by a debugger.</summary>
// typedef struct _EXCEPTION_DEBUG_INFO { EXCEPTION_RECORD ExceptionRecord; DWORD dwFirstChance;} EXCEPTION_DEBUG_INFO,
// *LPEXCEPTION_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679326(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679326")]
[StructLayout(LayoutKind.Sequential)]
public struct EXCEPTION_DEBUG_INFO
{
/// <summary>
/// An <c>EXCEPTION_RECORD</c> structure with information specific to the exception. This includes the exception code,
/// flags, address, a pointer to a related exception, extra parameters, and so on.
/// </summary>
public EXCEPTION_RECORD ExceptionRecord;
/// <summary>
/// A value that indicates whether the debugger has previously encountered the exception specified by the
/// <c>ExceptionRecord</c> member. If the <c>dwFirstChance</c> member is nonzero, this is the first time the debugger has
/// encountered the exception. Debuggers typically handle breakpoint and single-step exceptions when they are first
/// encountered. If this member is zero, the debugger has previously encountered the exception. This occurs only if,
/// during the search for structured exception handlers, either no handler was found or the exception was continued.
/// </summary>
public uint dwFirstChance;
}
/// <summary>Contains thread-creation information that can be used by a debugger.</summary>
// typedef struct _CREATE_THREAD_DEBUG_INFO { HANDLE hThread; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE
// lpStartAddress;} CREATE_THREAD_DEBUG_INFO,
// *LPCREATE_THREAD_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679287(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679287")]
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_THREAD_DEBUG_INFO
{
/// <summary>
/// A handle to the thread whose creation caused the debugging event. If this member is <c>NULL</c>, the handle is not
/// valid. Otherwise, the debugger has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the
/// thread, allowing the debugger to read from and write to the registers of the thread and control execution of the thread.
/// </summary>
public HTHREAD hThread;
/// <summary>
/// A pointer to a block of data. At offset 0x2C into this block is another pointer, called ThreadLocalStoragePointer,
/// that points to an array of per-module thread local storage blocks. This gives a debugger access to per-thread data in
/// the threads of the process being debugged using the same algorithms that a compiler would use.
/// </summary>
public IntPtr lpThreadLocalBase;
/// <summary>
/// A pointer to the starting address of the thread. This value may only be an approximation of the thread's starting
/// address, because any application with appropriate access to the thread can change the thread's context by using the
/// <c>SetThreadContext</c> function.
/// </summary>
//[MarshalAs(UnmanagedType.FunctionPtr)]
//public PTHREAD_START_ROUTINE lpStartAddress;
public IntPtr lpStartAddress;
}
/// <summary>Contains process creation information that can be used by a debugger.</summary>
// typedef struct _CREATE_PROCESS_DEBUG_INFO { HANDLE hFile; HANDLE hProcess; HANDLE hThread; LPVOID lpBaseOfImage; DWORD
// dwDebugInfoFileOffset; DWORD nDebugInfoSize; LPVOID lpThreadLocalBase; LPTHREAD_START_ROUTINE lpStartAddress; LPVOID
// lpImageName; WORD fUnicode;} CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
[PInvokeData("WinBase.h", MSDNShortId = "ms679286")]
[StructLayout(LayoutKind.Sequential)]
public struct CREATE_PROCESS_DEBUG_INFO
{
/// <summary>
/// <para>
/// A handle to the process's image file. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the debugger
/// can use the member to read from and write to the image file.
/// </para>
/// <para>When the debugger is finished with this file, it should close the handle using the <c>CloseHandle</c> function.</para>
/// </summary>
public HFILE hFile;
/// <summary>
/// A handle to the process. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the debugger can use the
/// member to read from and write to the process's memory.
/// </summary>
public HPROCESS hProcess;
/// <summary>
/// A handle to the initial thread of the process identified by the <c>hProcess</c> member. If <c>hThread</c> param is
/// <c>NULL</c>, the handle is not valid. Otherwise, the debugger has <c>THREAD_GET_CONTEXT</c>,
/// <c>THREAD_SET_CONTEXT</c>, and <c>THREAD_SUSPEND_RESUME</c> access to the thread, allowing the debugger to read from
/// and write to the registers of the thread and to control execution of the thread.
/// </summary>
public HTHREAD hThread;
/// <summary>The base address of the executable image that the process is running.</summary>
public IntPtr lpBaseOfImage;
/// <summary>The offset to the debugging information in the file identified by the <c>hFile</c> member.</summary>
public uint dwDebugInfoFileOffset;
/// <summary>
/// The size of the debugging information in the file, in bytes. If this value is zero, there is no debugging information.
/// </summary>
public uint nDebugInfoSize;
/// <summary>
/// A pointer to a block of data. At offset 0x2C into this block is another pointer, called , that points to an array of
/// per-module thread local storage blocks. This gives a debugger access to per-thread data in the threads of the process
/// being debugged using the same algorithms that a compiler would use.
/// </summary>
public IntPtr lpThreadLocalBase;
/// <summary>
/// A pointer to the starting address of the thread. This value may only be an approximation of the thread's starting
/// address, because any application with appropriate access to the thread can change the thread's context by using the
/// <c>SetThreadContext</c> function.
/// </summary>
//[MarshalAs(UnmanagedType.FunctionPtr)]
//public PTHREAD_START_ROUTINE lpStartAddress;
public IntPtr lpStartAddress;
/// <summary>
/// <para>
/// A pointer to the file name associated with the <c>hFile</c> member. This parameter may be <c>NULL</c>, or it may
/// contain the address of a string pointer in the address space of the process being debugged. That address may, in
/// turn, either be <c>NULL</c> or point to the actual filename. If <c>fUnicode</c> is a nonzero value, the name string
/// is Unicode; otherwise, it is ANSI.
/// </para>
/// <para>
/// This member is strictly optional. Debuggers must be prepared to handle the case where <c>lpImageName</c> is
/// <c>NULL</c> or * <c>lpImageName</c> (in the address space of the process being debugged) is <c>NULL</c>.
/// Specifically, the system does not provide an image name for a create process event, and will not likely pass an image
/// name for the first DLL event. The system also does not provide this information in the case of debug events that
/// originate from a call to the <c>DebugActiveProcess</c> function.
/// </para>
/// </summary>
public IntPtr lpImageName;
/// <summary>
/// A value that indicates whether a file name specified by the <c>lpImageName</c> member is Unicode or ANSI. A nonzero
/// value indicates Unicode; zero indicates ANSI.
/// </summary>
public ushort fUnicode;
}
/// <summary>Contains the exit code for a terminating process.</summary>
// typedef struct _EXIT_PROCESS_DEBUG_INFO { DWORD dwExitCode;} EXIT_PROCESS_DEBUG_INFO, *LPEXIT_PROCESS_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679334(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679334")]
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_PROCESS_DEBUG_INFO
{
/// <summary>The exit code for the process.</summary>
public uint dwExitCode;
}
/// <summary>Contains the exit code for a terminating thread.</summary>
// typedef struct _EXIT_THREAD_DEBUG_INFO { DWORD dwExitCode;} EXIT_THREAD_DEBUG_INFO, *LPEXIT_THREAD_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms679335(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms679335")]
[StructLayout(LayoutKind.Sequential)]
public struct EXIT_THREAD_DEBUG_INFO
{
/// <summary>The exit code for the thread.</summary>
public uint dwExitCode;
}
/// <summary>Contains information about a dynamic-link library (DLL) that has just been loaded.</summary>
// typedef struct _LOAD_DLL_DEBUG_INFO { HANDLE hFile; LPVOID lpBaseOfDll; DWORD dwDebugInfoFileOffset; DWORD nDebugInfoSize;
// LPVOID lpImageName; WORD fUnicode;} LOAD_DLL_DEBUG_INFO, *LPLOAD_DLL_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680351(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680351")]
[StructLayout(LayoutKind.Sequential)]
public struct LOAD_DLL_DEBUG_INFO
{
/// <summary>
/// <para>
/// A handle to the loaded DLL. If this member is <c>NULL</c>, the handle is not valid. Otherwise, the member is opened
/// for reading and read-sharing in the context of the debugger.
/// </para>
/// <para>When the debugger is finished with this file, it should close the handle using the <c>CloseHandle</c> function.</para>
/// </summary>
public HFILE hFile;
/// <summary>A pointer to the base address of the DLL in the address space of the process loading the DLL.</summary>
public IntPtr lpBaseOfDll;
/// <summary>
/// The offset to the debugging information in the file identified by the <c>hFile</c> member, in bytes. The system
/// expects the debugging information to be in CodeView 4.0 format. This format is currently a derivative of Common
/// Object File Format (COFF).
/// </summary>
public uint dwDebugInfoFileOffset;
/// <summary>
/// The size of the debugging information in the file, in bytes. If this member is zero, there is no debugging information.
/// </summary>
public uint nDebugInfoSize;
/// <summary>
/// <para>
/// A pointer to the file name associated with <c>hFile</c>. This member may be <c>NULL</c>, or it may contain the
/// address of a string pointer in the address space of the process being debugged. That address may, in turn, either be
/// <c>NULL</c> or point to the actual filename. If <c>fUnicode</c> is a nonzero value, the name string is Unicode;
/// otherwise, it is ANSI.
/// </para>
/// <para>
/// This member is strictly optional. Debuggers must be prepared to handle the case where <c>lpImageName</c> is
/// <c>NULL</c> or * <c>lpImageName</c> (in the address space of the process being debugged) is <c>NULL</c>.
/// Specifically, the system will never provide an image name for a create process event, and it will not likely pass an
/// image name for the first DLL event. The system will also never provide this information in the case of debugging
/// events that originate from a call to the <c>DebugActiveProcess</c> function.
/// </para>
/// </summary>
public IntPtr lpImageName;
/// <summary>
/// A value that indicates whether a filename specified by <c>lpImageName</c> is Unicode or ANSI. A nonzero value for
/// this member indicates Unicode; zero indicates ANSI.
/// </summary>
public ushort fUnicode;
}
/// <summary>Contains information about a dynamic-link library (DLL) that has just been unloaded.</summary>
// typedef struct _UNLOAD_DLL_DEBUG_INFO { LPVOID lpBaseOfDll;} UNLOAD_DLL_DEBUG_INFO, *LPUNLOAD_DLL_DEBUG_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms681403(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms681403")]
[StructLayout(LayoutKind.Sequential)]
public struct UNLOAD_DLL_DEBUG_INFO
{
/// <summary>A pointer to the base address of the DLL in the address space of the process unloading the DLL.</summary>
public IntPtr lpBaseOfDll;
}
/// <summary>Contains the address, format, and length, in bytes, of a debugging string.</summary>
// typedef struct _OUTPUT_DEBUG_STRING_INFO { LPSTR lpDebugStringData; WORD fUnicode; WORD nDebugStringLength;} OUTPUT_DEBUG_STRING_INFO,
// *LPOUTPUT_DEBUG_STRING_INFO;// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680545(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680545")]
[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 <c>ReadProcessMemory</c>
/// 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;
/// <summary>Gets the debugging string in the calling process's address space.</summary>
public string DebugString => ReadString(lpDebugStringData, fUnicode, nDebugStringLength);
}
/// <summary>Contains the error that caused the RIP debug event.</summary>
// typedef struct _RIP_INFO { DWORD dwError; DWORD dwType;} RIP_INFO, *LPRIP_INFO; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680587(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms680587")]
[StructLayout(LayoutKind.Sequential)]
public struct RIP_INFO
{
/// <summary>The error that caused the RIP debug event. For more information, see Error Handling.</summary>
public uint dwError;
/// <summary>
/// <para>
/// Any additional information about the type of error that caused the RIP debug event. This member can be one of the
/// following values.
/// </para>
/// <para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>SLE_ERROR = 0x00000001</term>
/// <term>Indicates that invalid data was passed to the function that failed. This caused the application to fail.</term>
/// </item>
/// <item>
/// <term>SLE_MINORERROR = 0x00000002</term>
/// <term>
/// Indicates that invalid data was passed to the function, but the error probably will not cause the application to fail.
/// </term>
/// </item>
/// <item>
/// <term>SLE_WARNING = 0x00000003</term>
/// <term>Indicates that potentially invalid data was passed to the function, but the function completed processing.</term>
/// </item>
/// <item>
/// <term>0</term>
/// <term>Indicates that only dwError was set.</term>
/// </item>
/// </list>
/// </para>
/// </summary>
public uint dwType;
}
}
private static string ReadString(IntPtr data, ushort fUni, ushort len)
{
return StringHelper.GetString(data, fUni != 0 ? CharSet.Unicode : CharSet.Ansi, len);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
@ -1126,6 +1127,26 @@ namespace Vanara.PInvoke
public IntPtr ContextRecord;
}
/// <summary>Common Exception codes</summary>
/// <remarks>
/// Users can define their own exception codes, so the code could be any value. The OS reserves bit 28 and may clear that for its own purposes
/// </remarks>
public enum ExceptionCode : uint
{
None = 0x0,
STATUS_BREAKPOINT = 0x80000003,
STATUS_SINGLESTEP = 0x80000004,
EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094,
/// <summary>Fired when debuggee gets a Control-C.</summary>
DBG_CONTROL_C = 0x40010005,
EXCEPTION_STACK_OVERFLOW = 0xC00000FD,
EXCEPTION_NONCONTINUABLE_EXCEPTION = 0xC0000025,
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
}
/// <summary>Describes an exception.</summary>
// typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID
// ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
@ -1138,7 +1159,7 @@ namespace Vanara.PInvoke
/// indicating a noncontinuable exception. Any attempt to continue execution after a noncontinuable exception causes the
/// <c>EXCEPTION_NONCONTINUABLE_EXCEPTION</c> exception.
/// </summary>
public uint ExceptionCode;
public ExceptionCode ExceptionCode;
/// <summary>
/// The exception flags. This member can be either zero, indicating a continuable exception, or <c>EXCEPTION_NONCONTINUABLE</c>
/// indicating a noncontinuable exception. Any attempt to continue execution after a noncontinuable exception causes the
@ -1157,6 +1178,32 @@ namespace Vanara.PInvoke
/// <c>ExceptionInformation</c> array.
/// </summary>
public uint NumberParameters;
// From code at https://github.com/SymbolSource/Microsoft.Samples.Debugging/blob/master/src/debugger/NativeDebugWrappers/NativeImports.cs, it provides a work-around the problem a ByValArray causes when marshaling regarding alignment. It creates separate entries for each item in the array.
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = EXCEPTION_MAXIMUM_PARAMETERS)]
//public IntPtr[] ExceptionInformation;
private IntPtr ExceptionInformation0;
private IntPtr ExceptionInformation1;
private IntPtr ExceptionInformation2;
private IntPtr ExceptionInformation3;
private IntPtr ExceptionInformation4;
private IntPtr ExceptionInformation5;
private IntPtr ExceptionInformation6;
private IntPtr ExceptionInformation7;
private IntPtr ExceptionInformation8;
private IntPtr ExceptionInformation9;
private IntPtr ExceptionInformation10;
private IntPtr ExceptionInformation11;
private IntPtr ExceptionInformation12;
private IntPtr ExceptionInformation13;
private IntPtr ExceptionInformation14;
/// <summary>
/// An associated <c>EXCEPTION_RECORD</c> structure. Exception records can be chained together to provide additional
/// information when nested exceptions occur.
/// </summary>
public EXCEPTION_RECORD? ChainedRecord => ExceptionRecord.ToNullableStructure<EXCEPTION_RECORD>();
/// <summary>
/// <para>
/// An array of additional arguments that describe the exception. The <c>RaiseException</c> function can specify this array of
@ -1189,8 +1236,17 @@ namespace Vanara.PInvoke
/// </item>
/// </list>
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EXCEPTION_MAXIMUM_PARAMETERS, ArraySubType = UnmanagedType.SysUInt)]
public UIntPtr[] ExceptionInformation;
public IntPtr[] ExceptionInformation
{
get => new[] { ExceptionInformation0, ExceptionInformation1, ExceptionInformation2, ExceptionInformation3, ExceptionInformation4, ExceptionInformation5, ExceptionInformation6, ExceptionInformation7, ExceptionInformation8, ExceptionInformation9, ExceptionInformation10, ExceptionInformation11, ExceptionInformation12, ExceptionInformation13, ExceptionInformation14 };
set
{
if (value is null || value.Length != EXCEPTION_MAXIMUM_PARAMETERS)
throw new ArgumentOutOfRangeException(nameof(value));
for (int i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
this.SetFieldValue($"ExceptionInformation{i}", value[i]);
}
}
}
/// <summary>A safe handle for continue handler handles.</summary>

View File

@ -39,6 +39,9 @@ PACKAGE_ID, PACKAGE_INFO_REFERENCE, PACKAGE_VERSION, ENCLAVE_CREATE_INFO_SGX, EN
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net20|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net20' ">
<Reference Include="System" />
</ItemGroup>

View File

@ -0,0 +1,25 @@
using NUnit.Framework;
using System.Runtime.InteropServices;
using Vanara.InteropServices;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke.Tests
{
[TestFixture]
public class DebugApiTests
{
[Test]
public void TestMethod()
{
TestContext.WriteLine($"EXCEPTION_RECORD: {Marshal.SizeOf(typeof(EXCEPTION_RECORD))}");
TestContext.WriteLine($"DEBUG_EVENT.EXCEPTION_DEBUG_INFO: {Marshal.SizeOf(typeof(DEBUG_EVENT.EXCEPTION_DEBUG_INFO))}");
TestContext.WriteLine($"DEBUG_EVENT.EXCEPTION_INFO: {Marshal.SizeOf(typeof(DEBUG_EVENT.EXCEPTION_INFO))}");
var pid = GetCurrentProcessId();
DebugActiveProcess(pid);
{
Assert.That(WaitForDebugEvent(out var evt, 2000));
DebugActiveProcessStop(pid);
}
}
}
}

View File

@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -37,6 +38,7 @@
<Compile Include="InteropServices\SafeLocalHandleTests.cs" />
<Compile Include="Kernel32Tests.cs" />
<Compile Include="ConsoleTests.cs" />
<Compile Include="DebugApiTests.cs" />
<Compile Include="SnapshotTests.cs" />
<Compile Include="SysInfoTests.cs" />
</ItemGroup>
@ -56,7 +58,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit">
<Version>3.11.0</Version>
<Version>3.12.0</Version>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter">
<Version>3.13.0</Version>