├── Debugger ├── SymbolEngine.cpp ├── Res │ ├── Debugger.rc │ ├── resource.h │ └── Debugger.aps ├── Dasm │ ├── DasmEngine.cpp │ ├── Dasm.h │ ├── Utils.h │ ├── DasmInc.h │ ├── Utils.cpp │ └── Dasm.cpp ├── Debugger.vcxproj.user ├── Inc │ ├── SymbolEngine.h │ ├── DebuggerDP.h │ ├── CustomErrors.h │ ├── MenuItems.h │ ├── Debug.h │ ├── Assert.h │ ├── WndProc.h │ ├── Common.h │ ├── StringLengths.h │ ├── UICommon.h │ ├── UICreator.h │ ├── SourceHelpers.h │ ├── GuiManager.h │ ├── Logger.h │ ├── GuiDebugCommon.h │ ├── CustomEvents.h │ ├── Breakpoint.h │ ├── DebugHelpers.h │ └── DebugCommon.h ├── Lib │ └── include │ │ ├── StringFunctions.h │ │ ├── Helpers.h │ │ ├── CommonInclude.h │ │ ├── IOFunctions.h │ │ ├── MemFunctions.h │ │ ├── General.h │ │ ├── DbgHelpers.h │ │ ├── ProcessFunctions.h │ │ ├── GuiFunctions.h │ │ ├── Assert.h │ │ ├── InternalDefines.h │ │ ├── Queue.h │ │ ├── Defines.h │ │ ├── LinkedList.h │ │ ├── Stack.h │ │ ├── RArray.h │ │ ├── Hashtable.h │ │ └── BinarySearchTree.h ├── Assert.cpp ├── DebuggerDP.cpp ├── MenuItems.cpp ├── WinMain.cpp ├── Logger.cpp ├── Debugger.vcxproj.filters ├── Debugger.vcxproj ├── Breakpoint.cpp ├── UICreator.cpp ├── WndProc.cpp └── GuiManager.cpp ├── README ├── Debugger.sln └── .gitignore /Debugger/SymbolEngine.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\SymbolEngine.h" -------------------------------------------------------------------------------- /Debugger/Res/Debugger.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shishir993/debugger/HEAD/Debugger/Res/Debugger.rc -------------------------------------------------------------------------------- /Debugger/Res/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shishir993/debugger/HEAD/Debugger/Res/resource.h -------------------------------------------------------------------------------- /Debugger/Res/Debugger.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shishir993/debugger/HEAD/Debugger/Res/Debugger.aps -------------------------------------------------------------------------------- /Debugger/Dasm/DasmEngine.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shishir993/debugger/HEAD/Debugger/Dasm/DasmEngine.cpp -------------------------------------------------------------------------------- /Debugger/Debugger.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Debugger/Inc/SymbolEngine.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SYMBOLENGINE_H 3 | #define _SYMBOLENGINE_H 4 | 5 | #include 6 | #include 7 | 8 | 9 | 10 | #endif // _SYMBOLENGINE_H 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ** Second try at writing full fledged debugger** 2 | 3 | - This is a debugger that works with Windows 32bit PE files. 4 | - Written in C using plain old Win32 APIs 5 | - It is being developed as a debugger with its own GUI -------------------------------------------------------------------------------- /Debugger/Inc/DebuggerDP.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DEBUGGERDP_H 3 | #define _DEBUGGERDP_H 4 | 5 | #include "Common.h" 6 | #include "UICommon.h" 7 | 8 | BOOL CALLBACK DebuggerDP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 9 | 10 | #endif // _DEBUGGERDP_H 11 | -------------------------------------------------------------------------------- /Debugger/Inc/CustomErrors.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _CUSTOMERRORS_H 3 | #define _CUSTOMERRORS_H 4 | 5 | #define CE_WMAIN_ERROR 1 6 | #define CE_WNDPROC_INIT 2 7 | #define CE_DIALOG_ERROR_RETURN 3 8 | 9 | #define CE_ASSERT_FAILED 0x666 10 | 11 | #endif // _CUSTOMERRORS_H 12 | -------------------------------------------------------------------------------- /Debugger/Inc/MenuItems.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _MENUITEMS_H 3 | #define _MENUITEMS_H 4 | 5 | #include "Common.h" 6 | 7 | // Functions 8 | void vMiDebuggerInit(HMENU hMenu); 9 | void vMiDebugSessionStart(HMENU hMenu); 10 | void vMiDebugSessionEnd(HMENU hMenu); 11 | void vMiDebuggerRunning(HMENU hMenu); 12 | void vMiDebuggerDebugging(HMENU hMenu); 13 | 14 | #endif // _MENUITEMS_H 15 | -------------------------------------------------------------------------------- /Debugger/Inc/Debug.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DEBUG_H 3 | #define _DEBUG_H 4 | 5 | #include "Common.h" 6 | #include "UICreator.h" 7 | #include "Defines.h" 8 | #include "Breakpoint.h" 9 | #include "DebugCommon.h" 10 | 11 | #define EXITCODE_TARGET_TERM 0xDEAD 12 | 13 | // **** Functions **** 14 | DWORD WINAPI dwDebugThreadEntry(LPVOID lpvArgs); 15 | 16 | 17 | #endif // _DEBUG_H 18 | -------------------------------------------------------------------------------- /Debugger/Inc/Assert.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ASSERT_H 3 | #define _ASSERT_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include "StringLengths.h" 9 | #include "CustomErrors.h" 10 | 11 | #ifdef _DEBUG 12 | void vAssert(const char* psFile, UINT uLine); 13 | #define ASSERT(x) \ 14 | if(x) {} \ 15 | else \ 16 | vAssert(__FILE__, __LINE__) 17 | #else 18 | #define ASSERT(x) 19 | #endif 20 | 21 | #endif //_ASSERT_H 22 | -------------------------------------------------------------------------------- /Debugger/Dasm/Dasm.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DASM_H 3 | #define _DASM_H 4 | 5 | #include "DasmInc.h" 6 | #include "DasmEngine.h" 7 | #include "Utils.h" 8 | 9 | #define EXEFILEMAP_NAME L"InputFileMapName" 10 | 11 | int wmain(int argc, WCHAR **argv); 12 | BOOL fCmdArgsHandler(int argc, WCHAR **argv, WCHAR *pwszInFile, 13 | DWORD dwInFileBufSize); 14 | void vRunTests(); 15 | BOOL fCloseFile(HANDLE hFile, HANDLE hFileMapObj, 16 | HANDLE hFileView); 17 | 18 | #endif // _DASM_H -------------------------------------------------------------------------------- /Debugger/Inc/WndProc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _WNDPROC_H 3 | #define _WNDPROC_H 4 | 5 | #include "Common.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "UICommon.h" 11 | #include "Logger.h" 12 | #include "UICreator.h" 13 | #include "Defines.h" 14 | 15 | typedef struct _DbgSessionStart { 16 | BOOL fDebuggingActiveProcess; 17 | BOOL fBreakAtMain; 18 | DWORD dwTargetPID; 19 | WCHAR szTargetPath[SLEN_MAXPATH]; 20 | }DBG_SESSIONSTART, *PDBG_SESSIONSTART; 21 | 22 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 23 | 24 | #endif // _WNDPROC_H 25 | -------------------------------------------------------------------------------- /Debugger/Inc/Common.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _COMMON_H 3 | #define _COMMON_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Assert.h" 10 | #include "CustomErrors.h" 11 | #include "StringLengths.h" 12 | #include "SourceHelpers.h" 13 | #include "Logger.h" 14 | #include "CustomEvents.h" 15 | 16 | // ** CHelpLib includes ** 17 | 18 | #include "GuiFunctions.h" 19 | #include "MemFunctions.h" 20 | #include "LinkedList.h" 21 | #include "Hashtable.h" 22 | #include "ProcessFunctions.h" 23 | #include "StringFunctions.h" 24 | #include "General.h" 25 | 26 | #endif // _COMMON_H 27 | -------------------------------------------------------------------------------- /Debugger/Inc/StringLengths.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _STRINGLENGTHS_H 3 | #define _STRINGLENGTHS_H 4 | 5 | #define SLEN_COMMON16 16 6 | #define SLEN_COMMON32 32 7 | #define SLEN_COMMON64 64 8 | #define SLEN_COMMON128 128 9 | #define SLEN_INT16 8 10 | #define SLEN_INT32 16 11 | #define SLEN_LOGLINE 1024 12 | #define SLEN_MAXPATH 1024 13 | 14 | #define SLEN_EVENTNAMES SLEN_COMMON32 15 | #define SLEN_EXCEPTION_NAME SLEN_COMMON128 16 | 17 | #define SLEN_DWORDSTR_HEX 16 // DWORD value represented in hex with leading 0x 18 | 19 | #define SLEN_REGISTER_NAME 8 20 | 21 | #endif // _STRINGLENGTHS_H 22 | -------------------------------------------------------------------------------- /Debugger/Inc/UICommon.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UICOMMON_H 3 | #define _UICOMMON_H 4 | 5 | #include 6 | 7 | #include "..\Res\resource.h" 8 | 9 | // IDs for controls created on the fly 10 | #define IDC_MAINTAB 6601 11 | //#define IDC_EDIT_DISASS 6602 12 | //#define IDC_LIST_CALLSTACK 6603 13 | //#define IDC_LIST_REGISTERS 6604 14 | //#define IDC_LIST_THREADS 6605 15 | //#define IDC_TAB_BOTTOM 6606 16 | //#define IDC_EDIT_COMMAND 6607 17 | 18 | // UI 19 | #define PADDING_LONE 6 20 | #define PADDING_TOGETHER 3 21 | 22 | // UI Class names 23 | #define CNAME_EDIT L"EDIT" 24 | #define CNAME_LIST L"LISTBOX" 25 | #define CNAME_STATIC L"STATIC" 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Debugger/Lib/include/StringFunctions.h: -------------------------------------------------------------------------------- 1 | // StringFunctions.h 2 | // Contains functions that provide string operations 3 | // Shishir Bhat (http://www.shishirbhat.com) 4 | // History 5 | // 08/10/13 Initial version 6 | // 09/09/14 Refactor to store defs in individual headers. 7 | // 8 | 9 | #ifndef _STRINGFUNCTIONS_H 10 | #define _STRINGFUNCTIONS_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include "Defines.h" 17 | 18 | // ------------------------------------------- 19 | // Functions exported 20 | 21 | DllExpImp PCWSTR CHL_SzGetFilenameFromPath(_In_z_ PCWSTR pszFilepath, _In_ int numCharsInput); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif // _STRINGFUNCTIONS_H 28 | -------------------------------------------------------------------------------- /Debugger/Lib/include/Helpers.h: -------------------------------------------------------------------------------- 1 | 2 | // Helpers.h 3 | // Contains handy helper defines and functions 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 8 | 9 | #ifndef _HELPERS_H 10 | #define _HELPERS_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | // Pass a pointer and value to this, assignment takes place only if 17 | // the pointer is not NULL 18 | #define IFPTR_SETVAL(ptr, val) { if(ptr) *ptr = val; } 19 | 20 | #define IFPTR_FREE(ptr) if(ptr) { CHL_MmFree((void**)&ptr); } 21 | 22 | #define ISVALID_HANDLE(handle) (handle != NULL && handle != INVALID_HANDLE_VALUE) 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif // _HELPERS_H 29 | -------------------------------------------------------------------------------- /Debugger/Lib/include/CommonInclude.h: -------------------------------------------------------------------------------- 1 | 2 | // CommonInclude.h 3 | // Contains common includes, defs and typedefs 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 09/18/2014 Standardize keys and value types 8 | // 08/04/2015 Make individual headers usable by clients 9 | // 10 | 11 | #ifndef _COMMONINCLUDE_H 12 | #define _COMMONINCLUDE_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif // _COMMONINCLUDE_H 32 | -------------------------------------------------------------------------------- /Debugger/Assert.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\Assert.h" 3 | 4 | void vAssert(const char* pszFile, UINT uLine) 5 | { 6 | // ensure that all buffers are written out first 7 | fflush(NULL); 8 | fprintf(stderr, "Assertion failed in %s at Line %u\n", pszFile, uLine); 9 | fflush(stderr); 10 | 11 | // Adding a hard breakpoint because: 12 | // In GUI programs, there is usually no console window open to display the assertion failure. 13 | // Even when a GUI program explicitly opens a console window, exiting the program causes 14 | // the console also to be closed immediately. So we cannot see where the assertion failed. 15 | 16 | if(IsDebuggerPresent()) 17 | { 18 | fprintf(stderr, "Debugger is present. Causing a breakpoint exception.\n"); 19 | __asm int 3 20 | } 21 | 22 | exit(CE_ASSERT_FAILED); 23 | } 24 | -------------------------------------------------------------------------------- /Debugger/Inc/UICreator.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UICREATOR_H 3 | #define _UICREATOR_H 4 | 5 | #include "Common.h" 6 | #include "UICommon.h" 7 | 8 | typedef struct _TabPageInfo { 9 | int iTabIndex; 10 | HWND hMainTab; 11 | HWND hEditDisass; 12 | HWND hTabBottom; 13 | HWND hListCallStack; 14 | HWND hListRegisters; 15 | HWND hListThreads; 16 | HWND hEditCommand; 17 | HWND hStaticCommand; 18 | 19 | HFONT hFixedFont; 20 | }TABPAGEINFO, *PTABPAGEINFO; 21 | 22 | BOOL fCreateMainTabControl(HWND hMainWnd, __out HWND *phTabControl, __out DWORD *pdwErrCode); 23 | BOOL fCreateTabPage(HWND hTab, __out PTABPAGEINFO pstTabPageInfo, __out DWORD *pdwErrCode); 24 | void vDeleteTabPage(HWND hTab, PTABPAGEINFO pstTabPageInfo); 25 | BOOL fSetTabPageText(HWND hTab, int iTabIndex, PCWSTR pszTabText); 26 | 27 | #endif // _UICREATOR_H 28 | -------------------------------------------------------------------------------- /Debugger/Lib/include/IOFunctions.h: -------------------------------------------------------------------------------- 1 | 2 | // IOFunctions.h 3 | // Contains functions that provide IO operation services 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 10 | 11 | #ifndef _IOFUNCTIONS_H 12 | #define _IOFUNCTIONS_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "Defines.h" 19 | #include "MemFunctions.h" 20 | 21 | // ------------------------------------------- 22 | // Functions exported 23 | 24 | DllExpImp HRESULT CHL_IoReadLineFromStdin(_Inout_z_bytecap_x_(dwBufSize) PWSTR pszBuffer, _In_ DWORD dwBufSize); 25 | DllExpImp HRESULT CHL_IoCreateFileWithSize(_Out_ PHANDLE phFile, _In_z_ PWCHAR pszFilepath, _In_ int iSizeBytes); 26 | 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | 32 | #endif // _IOFUNCTIONS_H 33 | -------------------------------------------------------------------------------- /Debugger.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Debugger", "Debugger\Debugger.vcxproj", "{EDEFC84A-1AD6-4FA6-8042-E198F3172866}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {EDEFC84A-1AD6-4FA6-8042-E198F3172866}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {EDEFC84A-1AD6-4FA6-8042-E198F3172866}.Debug|Win32.Build.0 = Debug|Win32 14 | {EDEFC84A-1AD6-4FA6-8042-E198F3172866}.Release|Win32.ActiveCfg = Release|Win32 15 | {EDEFC84A-1AD6-4FA6-8042-E198F3172866}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Debugger/Lib/include/MemFunctions.h: -------------------------------------------------------------------------------- 1 | 2 | // MemFunctions.h 3 | // Contains functions that provide memory alloc/dealloc services 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 10 | 11 | #ifndef _MEMFUNCTIONS_H 12 | #define _MEMFUNCTIONS_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "Defines.h" 19 | 20 | // Custom error codes 21 | #define CHLE_MEM_ENOMEM 17000 22 | #define CHLE_MEM_GEN 17001 23 | 24 | // ------------------------------------------- 25 | // Functions exported 26 | 27 | DllExpImp HRESULT CHL_MmAlloc(_Out_cap_(uSizeBytes) PVOID *ppvAddr, _In_ size_t uSizeBytes, _In_opt_ PDWORD pdwError); 28 | DllExpImp void CHL_MmFree(_In_ PVOID *ppvToFree); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif // _MEMFUNCTIONS_H 35 | -------------------------------------------------------------------------------- /Debugger/Dasm/Utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTILS_H 3 | #define _UTILS_H 4 | 5 | #include 6 | #include "DasmInc.h" 7 | #include "DASMEngine.h" 8 | 9 | #define MOD_MASK 0xC0 // 1100 0000 10 | #define REG_MASK 0x38 // 0011 1000 11 | #define RM_MASK 0x07 // 0000 0111 12 | #define DBIT_MASK 0x02 // 0000 0010 13 | #define WBIT_MASK 0x01 // 0000 0001 14 | 15 | /* 16 | * Utility functions provided 17 | */ 18 | 19 | // Instruction utils 20 | void Util_vSplitModRMByte(BYTE bModRMValue, __out PBYTE pbMod, 21 | __out PBYTE pbReg, __out PBYTE pbRM); 22 | void Util_vGetDWBits(BYTE bOpcode, __out PBYTE pbDBit, __out PBYTE pbWBit); 23 | BOOL Util_fIsPrefix(BYTE bValue); 24 | 25 | // PE header related utils 26 | BOOL Util_fDumpIMAGE_IMPORT_DESCRIPTORS(DWORD rva, DWORD dwSize, 27 | PIMAGE_NT_HEADERS pNTHeaders, DWORD dwFileBase); 28 | 29 | // Other 30 | void Util_vTwosComplementByte(BYTE chSignedVal, __out PBYTE pchOut); 31 | void Util_vTwosComplementInt(INT iSignedVal, __out PINT piOut); 32 | 33 | 34 | #endif // _UTILS_H 35 | -------------------------------------------------------------------------------- /Debugger/Lib/include/General.h: -------------------------------------------------------------------------------- 1 | 2 | // General.h 3 | // Contains general helper functions 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 01/20/14 Initial version 7 | // 09/12/14 Naming convention modifications 8 | // 9 | 10 | #ifndef _GENERAL_H 11 | #define _GENERAL_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include "Defines.h" 18 | 19 | // ------------------------------------------- 20 | // Functions exported 21 | 22 | #if !defined(_WIN64) 23 | 24 | DllExpImp BOOL CHL_GnIsOverflowINT(_In_ int a, _In_ int b); 25 | DllExpImp BOOL CHL_GnIsOverflowUINT(_In_ UINT a, _In_ UINT b); 26 | 27 | #endif // _WIN64 28 | 29 | DllExpImp HRESULT CHL_GnCreateMemMapOfFile( 30 | _In_ HANDLE hFile, 31 | _In_ DWORD dwReqProtection, 32 | _Out_ PHANDLE phMapObj, 33 | _Out_ PHANDLE phMapView); 34 | 35 | // ------------------------------------------- 36 | // Functions used only within this library 37 | 38 | HRESULT CHL_GnOwnMutex(_In_ HANDLE hMutex); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif // _GENERAL_H 45 | -------------------------------------------------------------------------------- /Debugger/Inc/SourceHelpers.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _CODECHECKERS_H 3 | #define _CODECHECKERS_H 4 | 5 | #include 6 | 7 | #define NELEMS_ARRAY(arr_var) (sizeof(arr_var)/sizeof(arr_var[0])) 8 | 9 | #define ISNULL(PtrHandle) (PtrHandle == NULL) 10 | #define ISNULL_GOTO(PtrHandle, gotoLocation) if(ISNULL(PtrHandle)) { goto gotoLocation; } 11 | #define ISVALID_HANDLE(handle) (handle != NULL && handle != INVALID_HANDLE_VALUE) 12 | 13 | #define IFPTR_FREE(ptr) if(!ISNULL(ptr)) { CHL_MmFree((void**)&ptr); } 14 | #define FREE_HANDLE(handle) if(ISVALID_HANDLE(handle)) { CloseHandle(handle); } handle = NULL 15 | 16 | #define IFPTR_SETVAL(ptr, val) if(ptr) { *ptr = val; } 17 | #define SET_ERRORCODE(dwErrCode) { dwErrCode = GetLastError(); } 18 | #define SET_ERRORCODE_PTR(pdwErrCode) { if(!ISNULL(pdwErrCode)) { *pdwErrCode = GetLastError(); } } 19 | 20 | #define CONV_WCHARSIZE(bytes) (bytes * sizeof(WCHAR)) 21 | #define CONV_BYTES_wcsnlen_s(wstring, maxcount) ( (wcsnlen_s(wstring, maxcount) + 1) * sizeof(WCHAR) ) 22 | 23 | #endif // _CODECHECKERS_H 24 | -------------------------------------------------------------------------------- /Debugger/Inc/GuiManager.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _GUIMANAGER_H 3 | #define _GUIMANAGER_H 4 | 5 | #include "Common.h" 6 | #include 7 | 8 | #include "UICommon.h" 9 | #include "Defines.h" 10 | #include "GuiDebugCommon.h" 11 | 12 | #define CLEAR_EDITCONTROL(hEditControl) SendMessage(hEditControl, EM_SETSEL, 0, -1); SendMessage(hEditControl, EM_REPLACESEL, FALSE, (LPARAM)L"") 13 | 14 | BOOL fGuiInitialize(__out DWORD *pdwErrCode); 15 | void vGuiExit(); 16 | BOOL fGuiAddTab(int tabIndex, DWORD threadId, __out DWORD *pdwErrCode); 17 | BOOL fGuiRemTab(int tabIndex, __out DWORD *pdwErrCode); 18 | BOOL fGuiFindTab(int tabIndex, __out DWORD *pdwThreadId, __out DWORD *pdwErrCode); 19 | BOOL fOnExitDetachTargets(); 20 | 21 | BOOL fGuiGetOpenFilename(HWND hMainWindow, WCHAR *pszFilters, __out WCHAR *pszFilepath, DWORD dwBufSize, __out DWORD *pdwErrCode); 22 | 23 | BOOL CALLBACK fGetProcIdDP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 24 | BOOL CALLBACK fGetNewProgramDP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 25 | 26 | BOOL fGuiUpdateThreadsList(HWND hThreadListView, PLV_THREADINFO pstLvThreadInfo, int nItems); 27 | BOOL fGuiUpdateRegistersList(HWND hRegsListView, WCHAR *apszNames[], DWORD *padwValues, int nItems); 28 | 29 | #endif // _GUIMANAGER_H 30 | -------------------------------------------------------------------------------- /Debugger/Inc/Logger.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _LOGGER_H 3 | #define _LOGGER_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Assert.h" 11 | #include "StringLengths.h" 12 | #include "..\Res\resource.h" 13 | 14 | #define LOGTYPE_TRACE 0 15 | #define LOGTYPE_WARN 1 16 | #define LOGTYPE_ERROR 2 17 | 18 | #define logtrace(plogger, fmt, ...) vWriteLogType(LOGTYPE_TRACE, plogger, fmt, __VA_ARGS__) 19 | #define logwarn(plogger, fmt, ...) vWriteLogType(LOGTYPE_WARN, plogger, fmt, __VA_ARGS__) 20 | #define logerror(plogger, fmt, ...) vWriteLogType(LOGTYPE_ERROR, plogger, fmt, __VA_ARGS__) 21 | 22 | #ifdef _DEBUG 23 | #define dbgwprintf(fmt, ...) wprintf(fmt, __VA_ARGS__) 24 | #else 25 | #define dbgwprintf(fmt, ...) 26 | #endif 27 | 28 | typedef struct _Logger 29 | { 30 | HANDLE hMutex; 31 | HANDLE hLogFile; 32 | WCHAR szMutexName[SLEN_COMMON64]; 33 | }LOGGER, *PLOGGER; 34 | 35 | BOOL fInitializeLogger(WCHAR *pszLogFilepath, __out LOGGER *pLogger); 36 | void vTerminateLogger(LOGGER *pLogger); 37 | void vWriteLog(LOGGER *pLogger, const WCHAR* pszMessageFmt, ...); 38 | void vWriteLogType(int iLogLevel, PLOGGER pLogger, const WCHAR *pszMessageFmt, ...); 39 | 40 | #endif // _LOGGER_H 41 | -------------------------------------------------------------------------------- /Debugger/Lib/include/DbgHelpers.h: -------------------------------------------------------------------------------- 1 | 2 | // DbgHelpers.h 3 | // Defines and functions to help in debugging 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 8 | 9 | #ifndef _DBGHELPERS_H 10 | #define _DBGHELPERS_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /** 17 | * Original work from http://c.learncodethehardway.org/book/ex20.html 18 | * Modified/additions to my liking 19 | */ 20 | 21 | #define logtrace(M, ...) fprintf(stderr, "[TRACE] " M "\n", ##__VA_ARGS__) 22 | #define logerr(M, ...) fprintf(stderr, "[ERROR] " M "(lastError: %u)\n", ##__VA_ARGS__, GetLastError()) 23 | #define logwarn(M, ...) fprintf(stderr, "[WARN] " M "\n", ##__VA_ARGS__) 24 | #define loginfo(M, ...) fprintf(stderr, "[INFO] " M "\n", ##__VA_ARGS__) 25 | 26 | #ifdef _DEBUG 27 | 28 | #define logdbg(M, ...) fprintf(stdout, "[DEBUG] " M "\n", ##__VA_ARGS__) 29 | 30 | #define DBG_MEMSET(mem, size) ( memset(mem, 0xCE, size) ) 31 | 32 | #else 33 | #define logdbg(M, ...) 34 | 35 | #define NDBG_MEMSET(mem, size) ( memset(mem, 0x00, size) ) 36 | #define DBG_MEMSET(mem, size) NDBG_MEMSET(mem, size) 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif // _DBGHELPERS_H 44 | -------------------------------------------------------------------------------- /Debugger/Inc/GuiDebugCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Common.h" 4 | #include "UICreator.h" 5 | 6 | #define THTYPE_MAIN 0 7 | #define THTYPE_WORKER 1 8 | 9 | #define LV_REGS_NUMCOLUMNS 2 10 | #define LV_THREAD_NUMCOLUMNS 5 11 | 12 | #define FREEIF_GUIDBGCOMM(ptr) if(ptr && ptr->fFreeThis) { CHL_MmFree((void**)&ptr); } 13 | 14 | typedef int THTYPE; 15 | 16 | static WCHAR aszThreadTypes[][SLEN_COMMON32] = { L"Main", L"Worker" }; 17 | static WCHAR *apszRegNames[] = { L"EAX", L"EBX", L"ECX", L"EDX", L"ESI", L"EDI", L"ESP", L"EBP", L"EIP" }; 18 | 19 | typedef struct _GuiDbgComm { 20 | // Indicates whether the receiver must free this memory or not 21 | BOOL fFreeThis; 22 | 23 | // threadID which is sending/receiving the message 24 | DWORD dwThreadID; 25 | 26 | // tab index and handles to all tabitem children 27 | TABPAGEINFO stTabPageInfo; 28 | 29 | // Indicates whether Gui is sending the detach message due to debugger main window exit 30 | BOOL GD_fDetachOnDebuggerExit; 31 | 32 | }GUIDBGCOMM, *PGUIDBGCOMM; 33 | 34 | typedef struct ListView_ThreadInfo { 35 | DWORD dwThreadId; 36 | DWORD dwEIPLocation; 37 | WCHAR szFunction[SLEN_COMMON64]; 38 | THTYPE thType; 39 | INT iThreadPri; 40 | }LV_THREADINFO, *PLV_THREADINFO; 41 | -------------------------------------------------------------------------------- /Debugger/Inc/CustomEvents.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _CUSTOMEVENTS_H 3 | #define _CUSTOMEVENTS_H 4 | 5 | #include 6 | 7 | // Naming convention: 8 | // First two letters indicate source and destination. GD means Gui to Debug thread. 9 | // Second word indicates what the message is about(tab, menu items, ...) 10 | // 11 | #define GD_TAB_INFOCUS WM_USER 12 | #define GD_TAB_OUTFOCUS (WM_USER + 1) 13 | 14 | #define GD_MENU_CONTINUE (WM_USER + 2) 15 | #define GD_MENU_STEPINTO (WM_USER + 3) 16 | #define GD_MENU_STEPOVER (WM_USER + 4) 17 | #define GD_MENU_STEPOUT (WM_USER + 5) 18 | #define GD_MENU_BREAKALL (WM_USER + 6) 19 | #define GD_MENU_SUSPALL (WM_USER + 7) 20 | #define GD_MENU_RESALL (WM_USER + 8) 21 | #define GD_MENU_SUSPRES (WM_USER + 9) 22 | 23 | #define GD_SESS_TERM (WM_USER + 10) 24 | #define GD_SESS_DETACH (WM_USER + 11) 25 | #define GD_SESS_DUMPTERM (WM_USER + 12) 26 | 27 | #define DG_SESS_TERM (WM_USER + 70) 28 | 29 | // Start and end values for use in GetMessage() 30 | #define CUSTOM_GDEVENT_START GD_TAB_INFOCUS 31 | #define CUSTOM_GDEVENT_END GD_SESS_DUMPTERM 32 | 33 | // Start and end values of Debug->Gui messages 34 | #define CUSTOM_DGEVENT_START DG_SESS_TERM 35 | #define CUSTOM_DGEVENT_END DG_SESS_TERM 36 | 37 | #endif // _CUSTOMEVENTS_H 38 | -------------------------------------------------------------------------------- /Debugger/Lib/include/ProcessFunctions.h: -------------------------------------------------------------------------------- 1 | 2 | // ProcessFunctions.h 3 | // Contains functions that provide IO operation services 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 03/25/14 Initial version 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 10 | 11 | #ifndef _PROCESSFUNCTIONS_H 12 | #define _PROCESSFUNCTIONS_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "Defines.h" 19 | 20 | // Custom error codes 21 | #define CHLE_PROC_DOSHEADER 17150 22 | #define CHLE_PROC_TEXTSECHDR 17151 23 | #define CHLE_PROC_NOEXEC 17152 24 | 25 | // ------------------------------------------- 26 | // Functions exported 27 | 28 | DllExpImp HRESULT CHL_PsGetProcNameFromID(_In_ DWORD pid, _Inout_z_ WCHAR *pwsProcName, _In_ DWORD dwBufSize); 29 | DllExpImp HRESULT CHL_PsGetNtHeaders(_In_ HANDLE hMapView, _Out_ PIMAGE_NT_HEADERS *ppstNtHeaders); 30 | DllExpImp HRESULT CHL_PsGetPtrToCode( 31 | _In_ DWORD dwFileBase, 32 | _In_ PIMAGE_NT_HEADERS pNTHeaders, 33 | _Out_ PDWORD pdwCodePtr, 34 | _Out_ PDWORD pdwSizeOfData, 35 | _Out_ PDWORD pdwCodeSecVirtAddr); 36 | 37 | DllExpImp HRESULT CHL_PsGetEnclosingSectionHeader(_In_ DWORD rva, _In_ PIMAGE_NT_HEADERS pNTHeader, _Out_ PIMAGE_SECTION_HEADER *ppstSecHeader); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif // _PROCESSFUNCTIONS_H 44 | -------------------------------------------------------------------------------- /Debugger/DebuggerDP.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\DebuggerDP.h" 3 | 4 | BOOL CALLBACK DebuggerDP(HWND hDlg, UINT message, WPARAM /*wParam*/, LPARAM lParam) 5 | { 6 | RECT rcOwner; 7 | // RECT rcTabAdjust; 8 | 9 | switch(message) 10 | { 11 | case WM_INITDIALOG: 12 | { 13 | HWND hTabParent = NULL; 14 | 15 | ASSERT(lParam); 16 | 17 | hTabParent = (HWND)lParam; 18 | 19 | // Get owner client rect so that I can fill up 20 | // the complete space of owner's client area 21 | RECT rcTemp; 22 | GetClientRect(hTabParent, &rcOwner); 23 | CopyRect(&rcTemp, &rcOwner); 24 | TabCtrl_AdjustRect(hTabParent, FALSE, &rcOwner); 25 | 26 | POINT p; 27 | p.x = rcOwner.left; 28 | p.y = rcOwner.top; 29 | ClientToScreen(hTabParent, &p); 30 | 31 | SetWindowPos(hDlg, HWND_TOP, p.x, p.y, rcOwner.right, rcOwner.bottom, SWP_SHOWWINDOW); 32 | 33 | return TRUE; 34 | } 35 | 36 | case WM_SIZE: 37 | { 38 | break; 39 | } 40 | 41 | case WM_COMMAND: 42 | { 43 | // handle commands from child controls 44 | //switch(LOWORD(wParam)) 45 | //{ 46 | 47 | //} 48 | return FALSE; 49 | } 50 | 51 | case WM_CLOSE: 52 | { 53 | EndDialog(hDlg, 0); 54 | return TRUE; 55 | } 56 | 57 | }// switch(message) 58 | return FALSE; 59 | } 60 | -------------------------------------------------------------------------------- /Debugger/Lib/include/GuiFunctions.h: -------------------------------------------------------------------------------- 1 | 2 | // GuiFunctions.h 3 | // Contains functions that provide IO operation services 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 03/25/14 Initial version 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 10 | 11 | #ifndef _GUIFUNCTIONS_H 12 | #define _GUIFUNCTIONS_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "Defines.h" 19 | #include "MemFunctions.h" 20 | 21 | // ------------------------------------------- 22 | // Functions exported 23 | 24 | DllExpImp HRESULT CHL_GuiCenterWindow(_In_ HWND hWnd); 25 | 26 | // Given the window handle and the number of characters, returns the 27 | // width and height in pixels that will be occupied by a string of that 28 | // consisting of those number of characters 29 | DllExpImp HRESULT CHL_GuiGetTextArea(_In_ HWND hWindow, _In_ int nCharsInText, _Out_ int *pnPixelsWidth, _Out_ int *pnPixelsHeight); 30 | 31 | DllExpImp HRESULT CHL_GuiInitListViewColumns( 32 | _In_ HWND hList, 33 | _In_ WCHAR *apszColumNames[], 34 | _In_ int nColumns, 35 | _In_opt_ int *paiColumnSizePercent); 36 | 37 | DllExpImp HRESULT CHL_GuiAddListViewRow( 38 | _In_ HWND hList, 39 | _In_ WCHAR *apszItemText[], 40 | _In_ int nItems, 41 | _In_opt_ LPARAM lParam); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif // _GUIFUNCTIONS_H 48 | -------------------------------------------------------------------------------- /Debugger/Dasm/DasmInc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DASMINC_H 3 | #define _DASMINC_H 4 | 5 | #include "..\Inc\Common.h" 6 | 7 | //#define UNIT_TESTS_ONLY 8 | 9 | // input file types assigned to g_dwInputFileType 10 | #define DASM_FTYPE_EXE 0x0001 11 | #define DASM_FTYPE_DLL 0x0002 12 | 13 | #define DASM_VERSION_STR L"0.9" 14 | 15 | #define MAX_CODE_PARTS 4 16 | #define CODE_PART_CODE 0 17 | #define CODE_PART_IAT 1 18 | 19 | /* 20 | * Structures 21 | */ 22 | typedef struct _BINFILEINFO { 23 | PIMAGE_NT_HEADERS pNTHeaders; // pointer to NT headers when binary file mapped into memory 24 | DWORD dwVirtBaseOfCode; // ImageBase + BaseOfCode 25 | }BINFILEINFO; 26 | 27 | // struct: store the location of an area within the .text section 28 | // where there is no code (parts may be the IAT/...). 29 | typedef struct _NonCodeLoc { 30 | INT iPartType; 31 | DWORD dwFilePointer; // where in the file this part of code starts 32 | DWORD dwPartSize; // size of this part of code 33 | }NONCODE_LOC; 34 | 35 | // struct: Includes an array of NONCODE_LOC struct to specify the various 36 | // places in the .text/code section where there is no code but 37 | // other stuff like IAT. 38 | typedef struct _NCodeLocs { 39 | HANDLE hFileBase; 40 | INT nNonCodeParts; 41 | NONCODE_LOC aNonCodeLocs[MAX_CODE_PARTS]; 42 | }NCODE_LOCS; 43 | 44 | // Function comment skeleton 45 | /* fGetPtrNTHeaders() 46 | * 47 | * 48 | * Args: 49 | * 50 | * 51 | * RetVal: 52 | * 53 | */ 54 | 55 | #endif // _DASMINC_H 56 | -------------------------------------------------------------------------------- /Debugger/Lib/include/Assert.h: -------------------------------------------------------------------------------- 1 | 2 | // Assert.h 3 | // Contains functions that provides the ASSERT() service 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 06/23/13 Initial version 7 | // 8 | 9 | /******************************************************************************************** 10 | * ASSERT(x) is a debug-mode-only macro that is used to catch errors that must not 11 | * occur when software is released. It finds out bugs in the coding phase rather than 12 | * the testing phase. 13 | * 14 | * ASSERT accepts a relational expression as a macro-argument and tests whether it is 15 | * true. If it is true, nothing is done. If it is false, the user-defined _Assert() 16 | * function is called which prints the line number and filename in which the assertion 17 | * failed. 18 | * 19 | * Debug-mode-only is achieved using the #ifdef directive. 20 | * Code is compiled using Visual Studio 2010, which defines the macro _DEBUG in debug-mode. 21 | * In debug-mode _DEBUG is defined and in release-mode it is not defined. 22 | *******************************************************************************************/ 23 | 24 | #ifndef _ASSERT_H 25 | #define _ASSERT_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | #ifdef _DEBUG 35 | void vAssert(const char* psFile, unsigned int uLine); 36 | #define ASSERT(x) \ 37 | if(x) {} \ 38 | else \ 39 | vAssert(__FILE__, __LINE__) 40 | #else 41 | #define ASSERT(x) 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif // _ASSERT_H 49 | -------------------------------------------------------------------------------- /Debugger/Inc/Breakpoint.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _BREAKPOINTS_H 3 | #define _BREAKPOINTS_H 4 | 5 | #include "Common.h" 6 | #include "Defines.h" 7 | #include "StringLengths.h" 8 | #include "Defines.h" 9 | #include "DebugCommon.h" 10 | 11 | #define BPTYPE_USERSINGLEHIT 0x0001 // for single stepping (step {out|over}), run to cursor 12 | #define BPTYPE_USERMULTIHIT 0x0002 // user specified 13 | #define BPTYPE_DEBUGGERSINGLEHIT 0x0004 14 | #define BPTYPE_DEBUGGERMULTIHIT 0x0008 15 | 16 | #define BPTYPE_ASMLEVEL 0x0010 // breakpoint at a specific address target memory 17 | #define BPTYPE_SOURCELEVEL 0x0020 // breakpoint at a line number in a source file related to a specific exe/dll 18 | 19 | typedef struct _ActualBreakpoint { 20 | BOOL fResolved; 21 | DWORD dwAddrInTarget; 22 | BYTE bOrigCodeByte; 23 | }ACTUALBP, *PACTUALBP; 24 | 25 | // The below structure is the one stored as the linked list node 26 | typedef struct _Breakpoint { 27 | int id; 28 | int nReferences; 29 | 30 | BPTYPE bpType; 31 | 32 | int iLineNum; 33 | WCHAR szExecutableName[SLEN_MAXPATH]; 34 | WCHAR szSourceFileName[SLEN_MAXPATH]; 35 | 36 | ACTUALBP stActualBp; 37 | }BREAKPOINT, *PBREAKPOINT; 38 | 39 | // ** Functions ** 40 | BOOL fBpInitialize(__out PBPLIST *ppBreakpoints); 41 | BOOL fBpTerminate(PBPLIST pBreakpoints); 42 | 43 | BOOL fBpInsert(PBPLIST pstBpList, PBPINFO pstBpInfo, PTARGETINFO pstTargetInfo, __out OPTIONAL PINT piBpID); 44 | BOOL fBpRemove(PBPLIST pstBpList, PBPINFO pstBpInfo, PTARGETINFO pstTargetInfo); 45 | BOOL fBpFind(PBPLIST pstBpList, __inout PBPINFO pstBpInfo, PINT piBpID); 46 | 47 | #endif // _BREAKPOINTS_H 48 | -------------------------------------------------------------------------------- /Debugger/Inc/DebugHelpers.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DEBUGTHREADHELPERS_H 3 | #define _DEBUGTHREADHELPERS_H 4 | 5 | #include "Common.h" 6 | #include "Defines.h" 7 | #include "DebugCommon.h" 8 | #include "GuiDebugCommon.h" 9 | 10 | // Bit number of the TrapFlag in EFlags register 11 | #define BITPOS_EFLAGS_TF 8 12 | 13 | BOOL fGetExceptionName(DWORD excode, __out WCHAR *pwsBuffer, int bufSize); 14 | 15 | BOOL fAddThread(CHL_HTABLE *phtThreads, DWORD dwThreadId, LPCREATE_THREAD_DEBUG_INFO lpThreadInfo); 16 | BOOL fRemoveThread(CHL_HTABLE *phtThreads, DWORD dwThreadId, __out LPCREATE_THREAD_DEBUG_INFO lpThreadInfo); 17 | BOOL fGetThreadHandle(CHL_HTABLE *phtThreads, DWORD id, __out HANDLE *phThread); 18 | BOOL fDeleteThreadsTable(CHL_HTABLE *phtThreads); 19 | BOOL fSuspendAllThreads(CHL_HTABLE *phtThreads); 20 | BOOL fResumeAllThreads(CHL_HTABLE *phtThreads); 21 | BOOL fIsNtDllLoaded(CHL_HTABLE *phtDllTable, __out DWORD *pdwBaseAddress); 22 | 23 | // Breakpoint functions 24 | BOOL fBreakAtEntryPoint(PTARGETINFO pstTargetInfo); 25 | BOOL fHandleExceptionBreakpoint(PTARGETINFO pstTargetInfo, __out PDWORD pdwContinueStatus); 26 | BOOL fReInsertBPIf(PTARGETINFO pstTargetInfo, PREVBPINFO *pstBpInfo); 27 | BOOL fDecrementInstPointer(CHL_HTABLE *phtThreads, DWORD dwThreadId); 28 | BOOL fSetTrapFlag(CHL_HTABLE *phtThreads, DWORD dwThreadId); 29 | BOOL fClearTrapFlag(CHL_HTABLE *phtThreads, DWORD dwThreadId); 30 | 31 | void vSetContinueStatusFromUser(DWORD dwExceptionCode, DWORD dwExceptionAddress, BOOL fFirstChance, PDWORD pdwContinueStatus); 32 | 33 | // Debugger state changes 34 | void vSetMenuItemsState(PTARGETINFO pstTargetInfo); 35 | void vDebuggerStateChange(PTARGETINFO pstTargetInfo, int iNewState); 36 | 37 | // Gui management 38 | BOOL fUpdateThreadsListView(HWND hList, CHL_HTABLE *phtThreads, HANDLE hMainThread); 39 | BOOL fUpdateRegistersListView(HWND hList, DWORD dwThreadId); 40 | BOOL fShowDisassembly(PTARGETINFO pstTargetInfo, DWORD dwStartFromTargetAddress); 41 | 42 | #endif // _DEBUGTHREADHELPERS_H 43 | -------------------------------------------------------------------------------- /Debugger/Lib/include/InternalDefines.h: -------------------------------------------------------------------------------- 1 | 2 | // Defines.h 3 | // Contains common #defines, typedefs and data structures 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 09/18/2014 Standardize keys and value types. 7 | // 08/04/2015 Make individual headers usable by clients. 8 | // 01/19/2016 Provide a way to test if a CHL_VAL is occupied or not. 9 | // 10 | 11 | #ifndef CHL_INT_DEFINES_H 12 | #define CHL_INT_DEFINES_H 13 | 14 | #include "CommonInclude.h" 15 | #include "Assert.h" 16 | #include "DbgHelpers.h" 17 | #include "Helpers.h" 18 | #include "Defines.h" 19 | 20 | // ------------------------------------------- 21 | // #defs and typedefs 22 | 23 | #define IS_VALID_CHL_VALTYPE(vt) (((vt) > CHL_VT_START) && ((vt) < CHL_VT_END)) 24 | #define IS_INVALID_CHL_VALTYPE(vt) (! IS_VALID_CHL_VALTYPE(vt)) 25 | 26 | #define IS_VALID_CHL_KEYTYPE(kt) (((kt) > CHL_KT_START) && ((kt) < CHL_KT_END)) 27 | #define IS_INVALID_CHL_KEYTYPE(kt) (! IS_VALID_CHL_KEYTYPE(kt)) 28 | 29 | // Magic number denoting that a CHL_VAL is currently occupied 30 | // This is actually prime number 433494437 (see https://en.wikipedia.org/wiki/List_of_prime_numbers#Markov_primes) 31 | #define MAGIC_CHLVAL_OCCUPIED ((UINT)0x19D699A5) 32 | 33 | // ------------------------------------------- 34 | // Functions internal only 35 | 36 | HRESULT _CopyKeyIn(_In_ PCHL_KEY pChlKey, _In_ CHL_KEYTYPE keyType, _In_ PCVOID pvKey, _Inout_opt_ int iKeySize); 37 | HRESULT _CopyKeyOut 38 | ( 39 | _In_ PCHL_KEY pChlKey, 40 | _In_ CHL_KEYTYPE keyType, 41 | _Inout_ PVOID pvKeyOut, 42 | _Inout_opt_ PINT pKeyOutSize, 43 | _In_ BOOL fGetPointerOnly 44 | ); 45 | BOOL _IsDuplicateKey(_In_ PCHL_KEY pChlLeftKey, _In_ PCVOID pvRightKey, _In_ CHL_KEYTYPE keyType, _In_ int iKeySize); 46 | void _DeleteKey(_In_ PCHL_KEY pChlKey, _In_ CHL_KEYTYPE keyType); 47 | HRESULT _GetKeySize(_In_ PVOID pvKey, _In_ CHL_KEYTYPE keyType, _Inout_ PINT piKeySize); 48 | HRESULT _EnsureSufficientKeyBuf( 49 | _In_ PCHL_KEY pChlKey, 50 | _In_ int iSpecBufSize, 51 | _Inout_opt_ PINT piReqBufSize); 52 | 53 | HRESULT _CopyValIn(_In_ PCHL_VAL pChlVal, _In_ CHL_VALTYPE valType, _In_ PCVOID pvVal, _Inout_opt_ int iValSize); 54 | HRESULT _CopyValOut 55 | ( 56 | _In_ PCHL_VAL pChlVal, 57 | _In_ CHL_VALTYPE valType, 58 | _Inout_ PVOID pvValOut, 59 | _Inout_opt_ PINT pValOutSize, 60 | _In_ BOOL fGetPointerOnly 61 | ); 62 | BOOL _IsDuplicateVal(_In_ PCHL_VAL pLeftVal, _In_ PCVOID pRightVal, _In_ CHL_VALTYPE valType, _In_ int iValSize); 63 | void _DeleteVal(_In_ PCHL_VAL pChlVal, _In_ CHL_VALTYPE valType, _In_opt_ BOOL fFreePointerType); 64 | void _MarkValUnoccupied(_In_ PCHL_VAL pChlVal); 65 | void _MarkValOccupied(_In_ PCHL_VAL pChlVal); 66 | BOOL _IsValOccupied(_In_ PCHL_VAL pChlVal); 67 | HRESULT _GetValSize(_In_ PVOID pvVal, _In_ CHL_VALTYPE valType, _Inout_ PINT piValSize); 68 | HRESULT _EnsureSufficientValBuf( 69 | _In_ PCHL_VAL pChlVal, 70 | _In_ int iSpecBufSize, 71 | _Inout_opt_ PINT piReqBufSize); 72 | 73 | #endif // CHL_INT_DEFINES_H 74 | -------------------------------------------------------------------------------- /Debugger/Lib/include/Queue.h: -------------------------------------------------------------------------------- 1 | 2 | // Queue.h 3 | // Contains functions that provide IO operation services 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // Unknown history! 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 9 | 10 | #ifndef _CHL_QUEUE_H 11 | #define _CHL_QUEUE_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include "Defines.h" 18 | #include "LinkedList.h" 19 | #include "MemFunctions.h" 20 | 21 | // A Queue object structure 22 | typedef struct _Queue CHL_QUEUE, *PCHL_QUEUE; 23 | struct _Queue 24 | { 25 | int nCapacity; // unused currently 26 | int nCurItems; 27 | PCHL_LLIST pList; 28 | 29 | // Access Methods 30 | 31 | HRESULT (*Create) 32 | ( 33 | _Out_ PCHL_QUEUE *ppQueueObj, 34 | _In_ CHL_VALTYPE valType, 35 | _In_opt_ int nEstimatedItems 36 | ); 37 | 38 | HRESULT (*Destroy) 39 | ( 40 | _In_ PCHL_QUEUE pThis 41 | ); 42 | 43 | HRESULT (*Insert) 44 | ( 45 | _In_ PCHL_QUEUE pQueueObj, 46 | _In_ PCVOID pvValue, 47 | _In_ int nValSize 48 | ); 49 | 50 | HRESULT (*Delete) 51 | ( 52 | _In_ PCHL_QUEUE pQueueObj, 53 | _Inout_opt_ PVOID pValOut, 54 | _Inout_opt_ PINT piValBufSize, 55 | _In_opt_ BOOL fGetPointerOnly 56 | ); 57 | 58 | HRESULT (*Peek) 59 | ( 60 | _In_ PCHL_QUEUE pQueueObj, 61 | _Inout_opt_ PVOID pValOut, 62 | _Inout_opt_ PINT piValBufSize, 63 | _In_opt_ BOOL fGetPointerOnly 64 | ); 65 | 66 | HRESULT(*Find) 67 | ( 68 | _In_ PCHL_QUEUE pQueueObj, 69 | _In_ PCVOID pvValue, 70 | _In_ CHL_CompareFn pfnComparer, 71 | _In_opt_ PVOID pvValOut, 72 | _In_opt_ PINT piValBufSize, 73 | _In_opt_ BOOL fGetPointerOnly 74 | ); 75 | }; 76 | 77 | // ------------------------------------------- 78 | // Functions exported 79 | 80 | DllExpImp HRESULT CHL_DsCreateQ 81 | ( 82 | _Out_ PCHL_QUEUE *ppQueueObj, 83 | _In_ CHL_VALTYPE valType, 84 | _In_opt_ int nEstimatedItems 85 | ); 86 | 87 | DllExpImp HRESULT CHL_DsDestroyQ(_In_ PCHL_QUEUE pQueueObj); 88 | 89 | DllExpImp HRESULT CHL_DsInsertQ 90 | ( 91 | _In_ PCHL_QUEUE pQueueObj, 92 | _In_ PCVOID pvValue, 93 | _In_ int nValSize 94 | ); 95 | 96 | DllExpImp HRESULT CHL_DsDeleteQ 97 | ( 98 | _In_ PCHL_QUEUE pQueueObj, 99 | _Inout_opt_ PVOID pValOut, 100 | _Inout_opt_ PINT piValBufSize, 101 | _In_opt_ BOOL fGetPointerOnly 102 | ); 103 | 104 | DllExpImp HRESULT CHL_DsPeekQ 105 | ( 106 | _In_ PCHL_QUEUE pQueueObj, 107 | _Inout_opt_ PVOID pValOut, 108 | _Inout_opt_ PINT piValBufSize, 109 | _In_opt_ BOOL fGetPointerOnly 110 | ); 111 | 112 | DllExpImp HRESULT CHL_DsFindQ 113 | ( 114 | _In_ PCHL_QUEUE pQueueObj, 115 | _In_ PCVOID pvValue, 116 | _In_ CHL_CompareFn pfnComparer, 117 | _In_opt_ PVOID pvValOut, 118 | _In_opt_ PINT piValBufSize, 119 | _In_opt_ BOOL fGetPointerOnly 120 | ); 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif // _CHL_QUEUE_H -------------------------------------------------------------------------------- /Debugger/Lib/include/Defines.h: -------------------------------------------------------------------------------- 1 | 2 | // Defines.h 3 | // Contains common #defines, typedefs and data structures 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 09/09/2014 Refactor to store defs in individual headers. 7 | // 08/04/2015 Make individual headers usable by clients. 8 | // 01/19/2016 Provide a way to test if a CHL_VAL is occupied or not. 9 | // 10 | 11 | #ifndef CHL_DEFINES_H 12 | #define CHL_DEFINES_H 13 | 14 | #include 15 | #include 16 | 17 | // ------------------------------------------- 18 | // #defs and typedefs 19 | 20 | #ifdef CHELPLIB_EXPORTS 21 | #define DllExpImp __declspec( dllexport ) 22 | #else 23 | #define DllExpImp __declspec( dllimport ) 24 | #endif // CHELPLIB_EXPORTS 25 | 26 | #ifndef PCVOID 27 | typedef PVOID const PCVOID; 28 | #endif 29 | 30 | // A generic compare function used to compare either two keys or two values. 31 | // The function must return - 32 | // 0 if both left and right are equal 33 | // 1 if right is greater than left 34 | // -1 if right is lesser than left 35 | typedef int (*CHL_CompareFn)(_In_ PCVOID pvLeft, _In_ PCVOID pvRight); 36 | 37 | // ------------------------------------------- 38 | // Structures 39 | 40 | union _tagCHL_KEYDEF { 41 | PSTR pszKey; 42 | PWSTR pwszKey; 43 | int iKey; 44 | UINT uiKey; 45 | PVOID pvKey; 46 | }; 47 | 48 | union _tagCHL_VALDEF { 49 | int iVal; 50 | UINT uiVal; 51 | double dVal; 52 | PSTR pszVal; // Pointer to ANSI string(value is allocated on heap) 53 | PWSTR pwszVal; // Pointer to wide string(value is allocated on heap) 54 | PVOID pvPtr; // Stores a pointer(any type)(value is allocated on heap) 55 | PVOID pvUserObj; // Pointer to user object(value is allocated on heap) 56 | }; 57 | 58 | typedef struct CHL_KEY 59 | { 60 | // Num. of bytes as size of key 61 | int iKeySize; 62 | 63 | // Storage for the key 64 | union _tagCHL_KEYDEF keyDef; 65 | 66 | }CHL_KEY, *PCHL_KEY; 67 | 68 | typedef struct CHL_VAL 69 | { 70 | // Num. of bytes as size of val 71 | int iValSize; 72 | 73 | // Magic number to denote whether occupied or not 74 | UINT magicOccupied; 75 | 76 | // Storage for the value 77 | union _tagCHL_VALDEF valDef; 78 | 79 | }CHL_VAL, *PCHL_VAL; 80 | 81 | // ------------------------------------------- 82 | // Enumerations 83 | 84 | // Key Types 85 | typedef enum 86 | { 87 | // Invalid value type 88 | CHL_KT_START, 89 | 90 | // Signed 32bit integer 91 | CHL_KT_INT32, 92 | 93 | // Unsigned 32bit integer 94 | CHL_KT_UINT32, 95 | 96 | // A pointer whose pointed-to address is the key 97 | CHL_KT_POINTER, 98 | 99 | // Null-terminated ANSI string 100 | CHL_KT_STRING, 101 | 102 | // Null-terminated Unicode(wide char) string 103 | CHL_KT_WSTRING, 104 | 105 | // Invalid value type 106 | CHL_KT_END 107 | }CHL_KEYTYPE; 108 | 109 | // Value Types 110 | typedef enum 111 | { 112 | // Invalid value type 113 | CHL_VT_START, 114 | 115 | // Signed 32bit integer 116 | CHL_VT_INT32, 117 | 118 | // Unsigned 32bit integer 119 | CHL_VT_UINT32, 120 | 121 | // Pointer of any type(pointed-to address is the value stored) 122 | CHL_VT_POINTER, 123 | 124 | // Any user object(data structure). 125 | CHL_VT_USEROBJECT, 126 | 127 | // Null-terminated ANSI string 128 | CHL_VT_STRING, 129 | 130 | // Null-terminated Unicode(wide char) string 131 | CHL_VT_WSTRING, 132 | 133 | // Invalid value type 134 | CHL_VT_END 135 | }CHL_VALTYPE; 136 | 137 | #endif // CHL_DEFINES_H 138 | -------------------------------------------------------------------------------- /Debugger/MenuItems.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\MenuItems.h" 3 | 4 | static void vOpenProgramProcess(HMENU hMenu, DWORD dwChangeTo); 5 | static void vTargetControl(HMENU hMenu, DWORD dwChangeTo); 6 | 7 | // vMiDebuggerInit() 8 | // 9 | void vMiDebuggerInit(HMENU hMenu) 10 | { 11 | ASSERT(ISVALID_HANDLE(hMenu)); 12 | 13 | // Everything is enabled by default when program starts up 14 | // So disable the target controls since no target is loaded at init 15 | vTargetControl(hMenu, MF_GRAYED); 16 | return; 17 | } 18 | 19 | // vMiDebugSessionStart() 20 | // 21 | void vMiDebugSessionStart(HMENU hMenu) 22 | { 23 | ASSERT(ISVALID_HANDLE(hMenu)); 24 | 25 | vTargetControl(hMenu, MF_ENABLED); 26 | vOpenProgramProcess(hMenu, MF_GRAYED); 27 | return; 28 | } 29 | 30 | // vMiDebugSessionEnd() 31 | // 32 | void vMiDebugSessionEnd(HMENU hMenu) 33 | { 34 | ASSERT(ISVALID_HANDLE(hMenu)); 35 | 36 | vOpenProgramProcess(hMenu, MF_ENABLED); 37 | vTargetControl(hMenu, MF_GRAYED); 38 | return; 39 | } 40 | 41 | void vMiDebuggerRunning(HMENU hMenu) 42 | { 43 | vOpenProgramProcess(hMenu, MF_GRAYED); 44 | 45 | EnableMenuItem(hMenu, IDM_TERMINATETARGET, MF_ENABLED); 46 | EnableMenuItem(hMenu, IDM_DETACHFROMTARGET, MF_ENABLED); 47 | EnableMenuItem(hMenu, IDM_DUMPANDTERMINATETARGET, MF_ENABLED); 48 | 49 | EnableMenuItem(hMenu, IDM_BREAKINTOTARGET, MF_ENABLED); 50 | 51 | EnableMenuItem(hMenu, IDM_SUSPENDALLTHREADS, MF_ENABLED); 52 | EnableMenuItem(hMenu, IDM_RESUMEALLTHREADS, MF_ENABLED); 53 | EnableMenuItem(hMenu, IDM_SUSPRESUME, MF_GRAYED); 54 | 55 | EnableMenuItem(hMenu, IDM_CONTINUE, MF_GRAYED); 56 | EnableMenuItem(hMenu, IDM_STEPINTO, MF_GRAYED); 57 | EnableMenuItem(hMenu, IDM_STEPOVER, MF_GRAYED); 58 | EnableMenuItem(hMenu, IDM_STEPOUT, MF_GRAYED); 59 | } 60 | 61 | void vMiDebuggerDebugging(HMENU hMenu) 62 | { 63 | EnableMenuItem(hMenu, IDM_TERMINATETARGET, MF_ENABLED); 64 | EnableMenuItem(hMenu, IDM_DETACHFROMTARGET, MF_ENABLED); 65 | EnableMenuItem(hMenu, IDM_DUMPANDTERMINATETARGET, MF_ENABLED); 66 | 67 | EnableMenuItem(hMenu, IDM_BREAKINTOTARGET, MF_GRAYED); 68 | 69 | // TODO: can we suspend /resume threads when the target has been suspended? 70 | EnableMenuItem(hMenu, IDM_SUSPENDALLTHREADS, MF_GRAYED); 71 | EnableMenuItem(hMenu, IDM_RESUMEALLTHREADS, MF_GRAYED); 72 | EnableMenuItem(hMenu, IDM_SUSPRESUME, MF_GRAYED); 73 | 74 | EnableMenuItem(hMenu, IDM_CONTINUE, MF_ENABLED); 75 | EnableMenuItem(hMenu, IDM_STEPINTO, MF_ENABLED); 76 | EnableMenuItem(hMenu, IDM_STEPOVER, MF_ENABLED); 77 | EnableMenuItem(hMenu, IDM_STEPOUT, MF_ENABLED); 78 | } 79 | 80 | static void vOpenProgramProcess(HMENU hMenu, DWORD dwChangeTo) 81 | { 82 | EnableMenuItem(hMenu, IDM_DEBUGPROGRAM, dwChangeTo); 83 | EnableMenuItem(hMenu, IDM_DEBUGPROCESS, dwChangeTo); 84 | } 85 | 86 | static void vTargetControl(HMENU hMenu, DWORD dwChangeTo) 87 | { 88 | EnableMenuItem(hMenu, IDM_TERMINATETARGET, dwChangeTo); 89 | EnableMenuItem(hMenu, IDM_DETACHFROMTARGET, dwChangeTo); 90 | EnableMenuItem(hMenu, IDM_DUMPANDTERMINATETARGET, dwChangeTo); 91 | 92 | EnableMenuItem(hMenu, IDM_CONTINUE, dwChangeTo); 93 | EnableMenuItem(hMenu, IDM_STEPINTO, dwChangeTo); 94 | EnableMenuItem(hMenu, IDM_STEPOVER, dwChangeTo); 95 | EnableMenuItem(hMenu, IDM_STEPOUT, dwChangeTo); 96 | 97 | EnableMenuItem(hMenu, IDM_BREAKINTOTARGET, dwChangeTo); 98 | 99 | EnableMenuItem(hMenu, IDM_SUSPENDALLTHREADS, dwChangeTo); 100 | EnableMenuItem(hMenu, IDM_RESUMEALLTHREADS, dwChangeTo); 101 | EnableMenuItem(hMenu, IDM_SUSPRESUME, dwChangeTo); 102 | } -------------------------------------------------------------------------------- /Debugger/Inc/DebugCommon.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DEBUGCOMMON_H 3 | #define _DEBUGCOMMON_H 4 | 5 | #include "Common.h" 6 | #include "UICreator.h" 7 | #include "Defines.h" 8 | 9 | #define DSTATE_INVALID 0 10 | 11 | // Target process is running and is not stopped by the debugger 12 | #define DSTATE_RUNNING 1 13 | 14 | // DO NOT process debug event loop, just wait for user input 15 | // and take action accordingly 16 | #define DSTATE_DEBUGGING 2 17 | 18 | // User is single stepping(step into) 19 | // Before: we are waiting for user input, DO NOT process debug event loop 20 | // After: user has pressed step into, process debug event loop(expect a SS exception) 21 | #define DSTATE_SINGLESTEP_BEFORE 3 22 | #define DSTATE_SINGLESTEP_AFTER 4 23 | 24 | // Debugger is using single step for its own purpose 25 | #define DSTATE_SINGLESTEP_DBG 5 26 | 27 | #define DSTATE_WAITFOR_DBGBREAK 6 28 | 29 | // Set by the Gui message loop handler or the debug event loop handler 30 | // indicating that the debug thread must exit now. This will be used 31 | // when the target process exits(either by itself or we killed it) or 32 | // we detach from it. 33 | #define DSTATE_EXIT 7 34 | 35 | // State after breakpoint hit. We must wait for user input and DO NOT 36 | // let target process continue execution when in this state 37 | #define DSTATE_BREAKPOINTWAIT DSTATE_DEBUGGING 38 | 39 | #define DSTATE_START DSTATE_INVALID 40 | #define DSTATE_END DSTATE_EXIT 41 | 42 | // Action the user specified when an unexpected BP was encountered 43 | #define DBG_CONTCUSTOM_ABORT 10 44 | #define DBG_CONTCUSTOM_BREAK 11 45 | 46 | #define MAX_BREAKPOINTS 256 // maximum logical breakpoints 47 | 48 | typedef int BPTYPE; // specifies breakpoint type 49 | 50 | typedef struct _BreakpointInterface { 51 | int aiIdentifiers[MAX_BREAKPOINTS]; 52 | PCHL_LLIST pstLinkedListBp; 53 | }BPLIST, *PBPLIST; 54 | 55 | // Structure used to pass BP info between caller and callee 56 | typedef struct _BpInfo { 57 | int id; // specify when removing a breakpoint 58 | BPTYPE iBpType; 59 | 60 | PWCHAR pszExecutableName; 61 | PWCHAR pszSourceFileName; 62 | int iLineNum; 63 | 64 | DWORD dwTargetAddr; 65 | 66 | }BPINFO, *PBPINFO; 67 | 68 | typedef struct _DebugInfo { 69 | BOOL fDebuggingActiveProcess; 70 | BOOL fBreakAtMain; 71 | WCHAR szTargetPath[SLEN_MAXPATH]; 72 | DWORD dwProcessID; 73 | HWND hMainWindow; 74 | HMENU hMainMenu; 75 | WCHAR szInitSyncEvtName[SLEN_EVENTNAMES]; 76 | TABPAGEINFO stTabPageInfo; 77 | }DEBUGINFO, *PDEBUGINFO; 78 | 79 | typedef struct _PrevBpInfo { 80 | // Breakpoint hit in which target thread 81 | DWORD dwThreadId; 82 | 83 | // Info about the breakpoint that was hit 84 | BPINFO stBpInfo; 85 | }PREVBPINFO; 86 | 87 | typedef struct _TargetInfo { 88 | PDEBUGINFO pstDebugInfoFromGui; 89 | 90 | BOOL fCreateProcessEventRecvd; 91 | 92 | DWORD dwPID; 93 | DWORD dwMainThreadID; 94 | 95 | CREATE_PROCESS_DEBUG_INFO stProcessInfo; 96 | 97 | HANDLE hFileMapObj; 98 | HANDLE hFileMapView; 99 | 100 | PIMAGE_NT_HEADERS pstNtHeaders; 101 | DWORD dwCodeStart; 102 | DWORD dwCodeSize; 103 | DWORD dwCodeSecVirtAddr; 104 | 105 | CHL_HTABLE *phtDllsLoaded; 106 | CHL_HTABLE *phtThreads; 107 | PBPLIST pListBreakpoint; 108 | PREVBPINFO stPrevBpInfo; 109 | 110 | // To store info during single stepping (using TF) 111 | DWORD dwSSThreadId; 112 | DWORD dwSSTargetAddr; 113 | 114 | int nCurThreads; 115 | int nTotalProcesses; 116 | int nTotalThreads; 117 | 118 | int nCurDllsLoaded; 119 | int nTotalDllsLoaded; 120 | 121 | int iDebugState; 122 | int iPrevDebugState; 123 | 124 | BOOL fDetachOnDebuggerExit; 125 | 126 | LPDEBUG_EVENT lpDebugEvent; 127 | }TARGETINFO, *PTARGETINFO; 128 | 129 | #endif // _DEBUGCOMMON_H 130 | -------------------------------------------------------------------------------- /Debugger/WinMain.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\Common.h" 3 | #include "Inc\WndProc.h" 4 | #include "Inc\UICommon.h" 5 | #include "Inc\Logger.h" 6 | 7 | #define WNDSIZE_WIDTH 1024 8 | #define WNDSIZE_HEIGHT 768 9 | 10 | HINSTANCE g_hMainInstance; 11 | 12 | LOGGER StLogger; 13 | PLOGGER pstLogger = &StLogger; 14 | 15 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) 16 | { 17 | HWND g_hMainWnd; 18 | MSG MainWndMsg; 19 | WNDCLASS MainWndClass; 20 | 21 | HACCEL hAccel; 22 | 23 | WCHAR szAppName[SLEN_COMMON64]; 24 | 25 | int iScreenX, iScreenY, iWndX, iWndY, iWidth, iHeight; 26 | RECT rcMainWnd; 27 | 28 | DBG_UNREFERENCED_PARAMETER(szCmdLine); 29 | DBG_UNREFERENCED_PARAMETER(hPrevInstance); 30 | 31 | // First, initialize logger 32 | if(!fInitializeLogger(L"OSD_Log.txt", &StLogger)) 33 | { 34 | MessageBox(NULL, L"Cannot initialize logger", L"Error", MB_ICONEXCLAMATION); 35 | return CE_WMAIN_ERROR; 36 | } 37 | 38 | g_hMainInstance = hInstance; 39 | 40 | LoadString(GetModuleHandle(NULL), IDS_PGMNAME, szAppName, _countof(szAppName)); 41 | 42 | // UI Window Class 43 | MainWndClass.style = CS_HREDRAW | CS_VREDRAW; 44 | MainWndClass.lpfnWndProc = WndProc; 45 | MainWndClass.cbClsExtra = 0; 46 | MainWndClass.cbWndExtra = 0; 47 | MainWndClass.hInstance = g_hMainInstance; 48 | MainWndClass.hIcon = NULL; 49 | MainWndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 50 | MainWndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 51 | MainWndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); 52 | MainWndClass.lpszClassName = szAppName; 53 | 54 | if(!RegisterClass(&MainWndClass)) 55 | { 56 | MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); 57 | return CE_WMAIN_ERROR; 58 | } 59 | 60 | // Initialize common controls 61 | InitCommonControls(); 62 | 63 | // Create the main window 64 | g_hMainWnd = CreateWindow(szAppName, // class name 65 | szAppName, // caption 66 | WS_CAPTION | 67 | WS_MINIMIZEBOX | 68 | WS_SYSMENU, // window style 69 | CW_USEDEFAULT, // initial X position 70 | CW_USEDEFAULT, // initial Y position 71 | WNDSIZE_WIDTH, // initial X size 72 | WNDSIZE_HEIGHT, // initial Y size 73 | NULL, // parent window handle 74 | NULL, // window menu handle 75 | g_hMainInstance, // program instance handle 76 | NULL); 77 | 78 | // exit if window was not created 79 | if( !g_hMainWnd ) 80 | { 81 | MessageBox(0, L"Main Window creation error. Cannot continue.", 0, 0); 82 | return CE_WMAIN_ERROR; 83 | } 84 | 85 | // Init accelerators 86 | hAccel = LoadAccelerators(g_hMainInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); 87 | if(!hAccel) 88 | { 89 | MessageBox(g_hMainWnd, L"Initialization failed. See log file.", L"Error", MB_OK | MB_ICONSTOP); 90 | logerror(pstLogger, L"LoadAccelerators() failed %u", GetLastError()); 91 | return CE_WMAIN_ERROR; 92 | } 93 | 94 | // centre the main window in the screen 95 | 96 | // get the screen co-ordinates 97 | iScreenX = GetSystemMetrics(SM_CXSCREEN); 98 | iScreenY = GetSystemMetrics(SM_CYSCREEN); 99 | 100 | // get window rect and calculate the main window dimensions 101 | GetWindowRect(g_hMainWnd, &rcMainWnd); 102 | iWidth = rcMainWnd.right - rcMainWnd.left; 103 | iHeight = rcMainWnd.bottom - rcMainWnd.top; 104 | 105 | // calculate the new co-ordinates for the main window 106 | iWndX = iScreenX / 2 - iWidth / 2; 107 | iWndY = iScreenY / 2 - iHeight / 2; 108 | 109 | MoveWindow(g_hMainWnd, iWndX, iWndY, iWidth, iHeight, FALSE); 110 | 111 | ShowWindow(g_hMainWnd, iCmdShow); 112 | UpdateWindow(g_hMainWnd); 113 | 114 | while( GetMessage(&MainWndMsg, NULL, 0, 0) ) 115 | { 116 | if(!TranslateAccelerator(g_hMainWnd, hAccel, &MainWndMsg)) 117 | { 118 | TranslateMessage(&MainWndMsg); 119 | DispatchMessage(&MainWndMsg); 120 | } 121 | } 122 | 123 | return MainWndMsg.wParam; 124 | } 125 | -------------------------------------------------------------------------------- /Debugger/Lib/include/LinkedList.h: -------------------------------------------------------------------------------- 1 | 2 | // LinkedList.h 3 | // Contains functions that implement a linked list data structure 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 04/05/14 Initial version 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 2016/01/30 Replace compare function with the standard CHL_CompareFn type 10 | // 11 | 12 | #ifndef _LINKEDLIST_H 13 | #define _LINKEDLIST_H 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #include "Defines.h" 20 | 21 | 22 | typedef struct _LlNode { 23 | CHL_VAL chlVal; 24 | struct _LlNode *pleft; 25 | struct _LlNode *pright; 26 | }LLNODE, *PLLNODE; 27 | 28 | typedef struct _LinkedList CHL_LLIST, *PCHL_LLIST; 29 | struct _LinkedList { 30 | int nCurNodes; 31 | int nMaxNodes; 32 | CHL_VALTYPE valType; 33 | PLLNODE pHead; 34 | PLLNODE pTail; 35 | 36 | // Access methods 37 | 38 | HRESULT (*Insert) 39 | ( 40 | PCHL_LLIST pLList, 41 | PCVOID pvVal, 42 | int iValSize 43 | ); 44 | 45 | HRESULT(*Remove) 46 | ( 47 | PCHL_LLIST pLList, 48 | PCVOID pvValToFind, 49 | BOOL fStopOnFirstFind, 50 | CHL_CompareFn pfnComparer 51 | ); 52 | 53 | HRESULT (*RemoveAt) 54 | ( 55 | PCHL_LLIST pLList, 56 | int iIndexToRemove, 57 | PVOID pvValOut, 58 | PINT piValBufSize, 59 | BOOL fGetPointerOnly 60 | ); 61 | 62 | HRESULT (*Peek) 63 | ( 64 | PCHL_LLIST pLList, 65 | int iIndexToPeek, 66 | PVOID pvValOut, 67 | PINT piValBufSize, 68 | BOOL fGetPointerOnly 69 | ); 70 | 71 | HRESULT (*Find) 72 | ( 73 | PCHL_LLIST pLList, 74 | PCVOID pvValToFind, 75 | CHL_CompareFn pfnComparer, 76 | PVOID pvValOut, 77 | PINT piValBufSize, 78 | BOOL fGetPointerOnly 79 | ); 80 | 81 | HRESULT (*Destroy)(PCHL_LLIST pLList); 82 | 83 | }; 84 | 85 | // ------------------------------------------- 86 | // Functions exported 87 | 88 | DllExpImp HRESULT CHL_DsCreateLL(_Out_ PCHL_LLIST *ppLList, _In_ CHL_VALTYPE valType, _In_opt_ int nEstEntries); 89 | 90 | // CHL_DsInsertLL() 91 | // Inserts an element into the linked list. Always inserts at the tail. 92 | // Insertion is an O(1) operation. 93 | // pLList: Pointer to a linked list object that was returned by a successful call 94 | // to CHL_DsCreateLL. 95 | // pvVal: The value or pointer to the value to be stored. All primitive types are passed by 96 | // value(like: CHL_DsInsertLL(pListObj, (PVOID)intValue, 0). All other complex 97 | // types are passed by reference(their address) and they are stored in the heap. 98 | // iValSize: Size in bytes of the value. Optional for primitive types, mandatory for others. 99 | // 100 | DllExpImp HRESULT CHL_DsInsertLL 101 | ( 102 | _In_ PCHL_LLIST pLList, 103 | _In_ PCVOID pvVal, 104 | _In_opt_ int iValSize 105 | ); 106 | 107 | DllExpImp HRESULT CHL_DsRemoveLL 108 | ( 109 | _In_ PCHL_LLIST pLList, 110 | _In_ PCVOID pvValToFind, 111 | _In_ BOOL fStopOnFirstFind, 112 | _In_ CHL_CompareFn pfnComparer 113 | ); 114 | 115 | DllExpImp HRESULT CHL_DsRemoveAtLL 116 | ( 117 | _In_ PCHL_LLIST pLList, 118 | _In_ int iIndexToRemove, 119 | _Inout_opt_ PVOID pvValOut, 120 | _Inout_opt_ PINT piValBufSize, 121 | _In_opt_ BOOL fGetPointerOnly 122 | ); 123 | 124 | DllExpImp HRESULT CHL_DsPeekAtLL 125 | ( 126 | _In_ PCHL_LLIST pLList, 127 | _In_ int iIndexToPeek, 128 | _Inout_opt_ PVOID pvValOut, 129 | _Inout_opt_ PINT piValBufSize, 130 | _In_opt_ BOOL fGetPointerOnly 131 | ); 132 | 133 | DllExpImp HRESULT CHL_DsFindLL 134 | ( 135 | _In_ PCHL_LLIST pLList, 136 | _In_ PCVOID pvValToFind, 137 | _In_ CHL_CompareFn pfnComparer, 138 | _Inout_opt_ PVOID pvValOut, 139 | _Inout_opt_ PINT piValBufSize, 140 | _In_opt_ BOOL fGetPointerOnly 141 | ); 142 | 143 | DllExpImp HRESULT CHL_DsDestroyLL(_In_ PCHL_LLIST pLList); 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif // _LINKEDLIST_H 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | *.db 81 | 82 | # Visual Studio profiler 83 | *.psess 84 | *.vsp 85 | *.vspx 86 | 87 | # TFS 2012 Local Workspace 88 | $tf/ 89 | 90 | # Guidance Automation Toolkit 91 | *.gpState 92 | 93 | # ReSharper is a .NET coding add-in 94 | _ReSharper*/ 95 | *.[Rr]e[Ss]harper 96 | *.DotSettings.user 97 | 98 | # JustCode is a .NET coding add-in 99 | .JustCode 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | _NCrunch_* 109 | .*crunch*.local.xml 110 | 111 | # MightyMoose 112 | *.mm.* 113 | AutoTest.Net/ 114 | 115 | # Web workbench (sass) 116 | .sass-cache/ 117 | 118 | # Installshield output folder 119 | [Ee]xpress/ 120 | 121 | # DocProject is a documentation generator add-in 122 | DocProject/buildhelp/ 123 | DocProject/Help/*.HxT 124 | DocProject/Help/*.HxC 125 | DocProject/Help/*.hhc 126 | DocProject/Help/*.hhk 127 | DocProject/Help/*.hhp 128 | DocProject/Help/Html2 129 | DocProject/Help/html 130 | 131 | # Click-Once directory 132 | publish/ 133 | 134 | # Publish Web Output 135 | *.[Pp]ublish.xml 136 | *.azurePubxml 137 | ## TODO: Comment the next line if you want to checkin your 138 | ## web deploy settings but do note that will include unencrypted 139 | ## passwords 140 | #*.pubxml 141 | 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | # The packages folder can be ignored because of Package Restore 147 | **/packages/* 148 | # except build/, which is used as an MSBuild target. 149 | !**/packages/build/ 150 | # Uncomment if necessary however generally it will be regenerated when needed 151 | #!**/packages/repositories.config 152 | 153 | # Windows Azure Build Output 154 | csx/ 155 | *.build.csdef 156 | 157 | # Windows Store app package directory 158 | AppPackages/ 159 | 160 | # Visual Studio cache files 161 | # files ending in .cache can be ignored 162 | *.[Cc]ache 163 | # but keep track of directories ending in .cache 164 | !*.[Cc]ache/ 165 | 166 | # Others 167 | ClientBin/ 168 | [Ss]tyle[Cc]op.* 169 | ~$* 170 | *~ 171 | *.dbmdl 172 | *.dbproj.schemaview 173 | *.pfx 174 | *.publishsettings 175 | node_modules/ 176 | orleans.codegen.cs 177 | 178 | # RIA/Silverlight projects 179 | Generated_Code/ 180 | 181 | # Backup & report files from converting an old project file 182 | # to a newer Visual Studio version. Backup files are not needed, 183 | # because we have git ;-) 184 | _UpgradeReport_Files/ 185 | Backup*/ 186 | UpgradeLog*.XML 187 | UpgradeLog*.htm 188 | 189 | # SQL Server files 190 | *.mdf 191 | *.ldf 192 | 193 | # Business Intelligence projects 194 | *.rdl.data 195 | *.bim.layout 196 | *.bim_*.settings 197 | 198 | # Microsoft Fakes 199 | FakesAssemblies/ 200 | 201 | # Node.js Tools for Visual Studio 202 | .ntvs_analysis.dat 203 | 204 | # Visual Studio 6 build log 205 | *.plg 206 | 207 | # Visual Studio 6 workspace options file 208 | *.opt 209 | 210 | # LightSwitch generated files 211 | GeneratedArtifacts/ 212 | _Pvt_Extensions/ 213 | ModelManifest.xml 214 | 215 | #Project specific 216 | Debugger/OSD_Log.txt 217 | -------------------------------------------------------------------------------- /Debugger/Lib/include/Stack.h: -------------------------------------------------------------------------------- 1 | 2 | // Stack.h 3 | // Stack implementation using resizable array 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 2015/12/08 Initial version 7 | // 8 | 9 | #ifndef _CHL_STACK_H 10 | #define _CHL_STACK_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include "Defines.h" 17 | #include "RArray.h" 18 | 19 | typedef struct _stack CHL_STACK, *PCHL_STACK; 20 | struct _stack 21 | { 22 | UINT topIndex; 23 | CHL_RARRAY rarray; 24 | 25 | // Function pointers 26 | 27 | HRESULT (*Create)(_Out_ PCHL_STACK pstk, _In_ CHL_VALTYPE valType, _In_opt_ UINT maxSize); 28 | HRESULT (*Destroy)(_In_ PCHL_STACK pstk); 29 | HRESULT (*Push)(_In_ PCHL_STACK pstk, _In_ PCVOID pVal, _In_opt_ int iBufSize); 30 | HRESULT (*Pop)(_In_ PCHL_STACK pstk, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize); 31 | HRESULT (*Top)(_In_ PCHL_STACK pstk, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize, 32 | _In_ BOOL fGetPointerOnly); 33 | HRESULT (*Peek)(_In_ PCHL_STACK pstk, _In_ UINT index, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize, 34 | _In_ BOOL fGetPointerOnly); 35 | UINT (*Size)(_In_ PCHL_STACK pstk); 36 | }; 37 | 38 | // Create a stack for the specified value type and optional max size specification. 39 | // Params: 40 | // pstk : Pointer to a CHL_STACK object that holds the created stack. 41 | // valType : Type of the values in the array. Values of enum CHL_VALTYPE. 42 | // maxSize : Optional. Maximum size the stack can grow to. Default is unlimited. 43 | DllExpImp HRESULT CHL_DsCreateSTK(_Out_ PCHL_STACK pstk, _In_ CHL_VALTYPE valType, _In_opt_ UINT maxSize); 44 | 45 | // Destroy a previously created stack. This frees all memory occupied by any existing stack elements. 46 | // Params: 47 | // pstk : Pointer to a previously created CHL_STACK object 48 | DllExpImp HRESULT CHL_DsDestroySTK(_In_ PCHL_STACK pstk); 49 | 50 | // Push specified value on top of the stack. 51 | // Params: 52 | // pstk : Pointer to a previously created CHL_STACK object 53 | // pVal : Value to be stored. For primitive types, this is the primitive value casted to a PCVOID. 54 | // iBufSize: Size of the value in bytes. For null-terminated strings, zero may be passed. 55 | // Ignored for primitive types. 56 | DllExpImp HRESULT CHL_DsPushSTK(_In_ PCHL_STACK pstk, _In_ PCVOID pVal, _In_opt_ int iBufSize); 57 | 58 | // Pop the value on top of the stack. 59 | // Params: 60 | // pstk : Pointer to a previously created CHL_STACK object 61 | // pValBuf : Optional. Pointer to a buffer to receive the popped value. 62 | // piBufSize : Optional. Pointer to UINT that specifies the provided buffer size. 63 | // If buffer size is insufficient, this argument will contain the required size on return. 64 | DllExpImp HRESULT CHL_DsPopSTK(_In_ PCHL_STACK pstk, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize); 65 | 66 | // Read value at top of stack. 67 | // Params: 68 | // pstk : Pointer to a previously created CHL_STACK object 69 | // pValBuf : Optional. Pointer to a buffer to receive the read value. 70 | // piBufSize : Optional. Pointer to UINT that specifies the provided buffer size. 71 | // If buffer size is insufficient, this argument will contain the required size on return. 72 | // Not required if fGetPointerOnly is TRUE. 73 | // fGetPointerOnly : Retrieve only a pointer to the value at top of stack. 74 | // 75 | DllExpImp HRESULT CHL_DsTopSTK(_In_ PCHL_STACK pstk, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize, 76 | _In_ BOOL fGetPointerOnly); 77 | 78 | // Read value at specified index in the stack. 79 | // Params: 80 | // pstk : Pointer to a previously created CHL_STACK object 81 | // index : Zero-based index. Get the index'th value (top of stack is index 0). 82 | // pValBuf : Optional. Pointer to a buffer to receive the read value. 83 | // piBufSize : Optional. Pointer to UINT that specifies the provided buffer size. 84 | // If buffer size is insufficient, this argument will contain the required size on return. 85 | // Not required if fGetPointerOnly is TRUE. 86 | // fGetPointerOnly : Retrieve only a pointer to the value at top of stack. 87 | DllExpImp HRESULT CHL_DsPeekSTK(_In_ PCHL_STACK pstk, _In_ UINT index, _Out_opt_ PVOID pValBuf, _Inout_opt_ PINT piBufSize, 88 | _In_ BOOL fGetPointerOnly); 89 | 90 | // Get the number of values in the stack currently. 91 | // Params: 92 | // pstk : Pointer to a previously created CHL_STACK object 93 | DllExpImp UINT CHL_DsSizeSTK(_In_ PCHL_STACK pstk); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif // _CHL_STACK_H 100 | -------------------------------------------------------------------------------- /Debugger/Lib/include/RArray.h: -------------------------------------------------------------------------------- 1 | 2 | // RArray.h 3 | // Resizable array implementation 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 2015/12/05 Initial version 7 | // 8 | 9 | #ifndef _RARRAY_H 10 | #define _RARRAY_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include "Defines.h" 17 | 18 | // The resizable array object 19 | typedef struct _rarray CHL_RARRAY, *PCHL_RARRAY; 20 | struct _rarray 21 | { 22 | UINT curSize; // Size of array currently 23 | UINT maxSize; // Upper limit for size growth. 0 = unlimited. 24 | CHL_VALTYPE vt; // Value type being held in the array 25 | CHL_VAL *pValArray; // Actual array holding the values 26 | 27 | // Function pointers 28 | 29 | HRESULT (*Create)(_Out_ PCHL_RARRAY pra, _In_ CHL_VALTYPE valType, _In_opt_ UINT initSize, _In_opt_ UINT maxSize); 30 | HRESULT (*Destroy)(_In_ PCHL_RARRAY pra); 31 | HRESULT (*Read)(_In_ PCHL_RARRAY pra, _In_ UINT index, _Out_opt_ PVOID pValBuf, 32 | _Inout_opt_ PINT piBufSize, _In_ BOOL fGetPointerOnly); 33 | HRESULT (*Write)(_In_ PCHL_RARRAY pra, _In_ UINT index, _In_ PCVOID pVal, _In_opt_ int iBufSize); 34 | HRESULT (*ClearAt)(_In_ PCHL_RARRAY pra, _In_ UINT index); 35 | HRESULT (*Resize)(_In_ PCHL_RARRAY pra, _In_ UINT newSize); 36 | UINT (*Size)(_In_ PCHL_RARRAY pra); 37 | UINT (*MaxSize)(_In_ PCHL_RARRAY pra); 38 | 39 | }; 40 | 41 | // Create a resizable array for the specified value type and optional size specifications. 42 | // Params: 43 | // pra : Pointer to a CHL_RARRAY object that holds the created resizable array 44 | // valType : Type of the values in the array. Values of enum CHL_VALTYPE. 45 | // initSize : Optional. Initial size of array. Default is 2. 46 | // maxSize : Optional. Maximum size array can grow to. Default is unlimited. 47 | // 48 | DllExpImp HRESULT CHL_DsCreateRA(_Out_ PCHL_RARRAY pra, _In_ CHL_VALTYPE valType, _In_opt_ UINT initSize, _In_opt_ UINT maxSize); 49 | 50 | // Destroy a previously created resizable array. This frees all memory occupied by the underlying array. 51 | // Params: 52 | // pra : Pointer to a previously created CHL_RARRAY object 53 | // 54 | DllExpImp HRESULT CHL_DsDestroyRA(_In_ PCHL_RARRAY pra); 55 | 56 | // Read the value at the specified index and return the value in the specified buffer 57 | // Params: 58 | // pra : Pointer to a previously created CHL_RARRAY object 59 | // index : Array index at which to perform the read. Must be less than the current size of array. 60 | // pValBuf : Optional. Pointer to a buffer to receive the read value. 61 | // piBufSize : Optional. Pointer to UINT that specifies the provided buffer size. 62 | // If buffer size is insufficient, this argument will contain the required size on return. 63 | // Not required if fGetPointerOnly is TRUE. 64 | // fGetPointerOnly : Retrieve only a pointer to the stored array value. 65 | // 66 | DllExpImp HRESULT CHL_DsReadRA(_In_ PCHL_RARRAY pra, _In_ UINT index, _Out_opt_ PVOID pValBuf, 67 | _Inout_opt_ PINT piBufSize, _In_ BOOL fGetPointerOnly); 68 | 69 | // Write to the specified array index, the specified value 70 | // Params: 71 | // pra : Pointer to a previously created CHL_RARRAY object 72 | // index : Array index at which to perform the write. Array is automatically resized if the index is 73 | // greater than the current size of array, up until maxSize is reached (if specified). 74 | // pVal : Value to be stored. For primitive types, this is the primitive value casted to a PCVOID. 75 | // iBufSize : Size of the value in bytes. For null-terminated strings, zero may be passed. 76 | // Ignored for primitive types. 77 | // 78 | DllExpImp HRESULT CHL_DsWriteRA(_In_ PCHL_RARRAY pra, _In_ UINT index, _In_ PCVOID pVal, _In_opt_ int iBufSize); 79 | 80 | // Clear the value stored at the specified index 81 | // Params: 82 | // pra : Pointer to a previously created CHL_RARRAY object 83 | // index : Array index at which to perform the clear. Must be less than the current size of array. 84 | // 85 | DllExpImp HRESULT CHL_DsClearAtRA(_In_ PCHL_RARRAY pra, _In_ UINT index); 86 | 87 | // Force resize of the resizable array to the specified size. New size can be lower or higher than current size. 88 | // Params: 89 | // pra : Pointer to a previously created CHL_RARRAY object 90 | // newSize : Size of the resized array 91 | // 92 | DllExpImp HRESULT CHL_DsResizeRA(_In_ PCHL_RARRAY pra, _In_ UINT newSize); 93 | 94 | // Retrieve current size of the resizable array 95 | // Params: 96 | // pra : Pointer to a previously created CHL_RARRAY object 97 | // 98 | DllExpImp UINT CHL_DsSizeRA(_In_ PCHL_RARRAY pra); 99 | 100 | // Retrieve maximum allowed size of the resizable array. Returns 0 if no limit is set. 101 | // Params: 102 | // pra : Pointer to a previously created CHL_RARRAY object 103 | // 104 | DllExpImp UINT CHL_DsMaxSizeRA(_In_ PCHL_RARRAY pra); 105 | 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif // _RARRAY_H 112 | -------------------------------------------------------------------------------- /Debugger/Logger.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\Logger.h" 3 | 4 | #define MAX_LOGLINE (SLEN_LOGLINE + 24) // accounting for the extra time info length and logtype 5 | 6 | static void vWriteLogInternal(int iLogType, LOGGER *pLogger, const WCHAR* pszMessage, int nLen); 7 | 8 | BOOL fInitializeLogger(WCHAR *pszLogFilepath, __out LOGGER *pLogger) 9 | { 10 | HANDLE hMutex = NULL; 11 | WCHAR szMutexNameTemp[SLEN_COMMON64]; 12 | 13 | HANDLE hFile = NULL; 14 | 15 | ASSERT(pszLogFilepath); 16 | ASSERT(pLogger); 17 | 18 | // todo: check return value 19 | LoadString(GetModuleHandle(NULL), IDS_LOGGERMUTEX, szMutexNameTemp, _countof(szMutexNameTemp) - SLEN_INT16); 20 | 21 | memset(pLogger, 0, sizeof(LOGGER)); 22 | 23 | srand(time(NULL)); 24 | swprintf_s(pLogger->szMutexName, _countof(pLogger->szMutexName), L"%s_%d", szMutexNameTemp, rand() % 65536); 25 | if(!(hMutex = CreateMutex(NULL, true, pLogger->szMutexName))) 26 | { 27 | // todo: do something similar to throw exception 28 | goto error_return; 29 | } 30 | 31 | // Create log file 32 | hFile = CreateFile(pszLogFilepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 33 | if(hFile == NULL) 34 | { 35 | // todo: do something similar to throw exception 36 | goto error_return; 37 | } 38 | 39 | pLogger->hMutex = hMutex; 40 | pLogger->hLogFile = hFile; 41 | 42 | ReleaseMutex(hMutex); 43 | vWriteLog(pLogger, L"Logger Initialized"); 44 | return TRUE; 45 | 46 | error_return: 47 | if(hFile) 48 | { 49 | CloseHandle(hFile); 50 | } 51 | 52 | if(hMutex) 53 | { 54 | ReleaseMutex(hMutex); 55 | CloseHandle(hMutex); 56 | } 57 | 58 | memset(pLogger, 0, sizeof(LOGGER)); 59 | return FALSE; 60 | } 61 | 62 | void vTerminateLogger(LOGGER *pLogger) 63 | { 64 | ASSERT(pLogger); 65 | ASSERT(pLogger->hMutex); 66 | ASSERT(pLogger->hLogFile); 67 | 68 | if(WaitForSingleObject(pLogger->hMutex, INFINITE) != WAIT_OBJECT_0) 69 | { 70 | // todo: something like an exception. SEH? 71 | return; 72 | } 73 | vWriteLog(pLogger, L"Logger Terminating..."); 74 | CloseHandle(pLogger->hLogFile); 75 | CloseHandle(pLogger->hMutex); 76 | 77 | // Mutex is never released 78 | 79 | memset(pLogger, 0, sizeof(LOGGER)); 80 | return; 81 | } 82 | 83 | // Writes a line of log to the logger. Uses LOGTYPE_TRACE to log the line. 84 | // 85 | void vWriteLog(LOGGER *pLogger, const WCHAR* pszMessageFmt, ...) 86 | { 87 | ASSERT(pszMessageFmt); 88 | 89 | va_list pArgs; 90 | WCHAR szLogMessage[SLEN_LOGLINE]; 91 | 92 | HRESULT hrReturn = S_OK; 93 | 94 | va_start(pArgs, pszMessageFmt); 95 | hrReturn = StringCchVPrintf(szLogMessage, _countof(szLogMessage), pszMessageFmt, pArgs); 96 | va_end(pArgs); 97 | 98 | if(FAILED(hrReturn)) 99 | { 100 | // todo: 101 | return; 102 | } 103 | 104 | vWriteLogInternal(LOGTYPE_TRACE, pLogger, szLogMessage, wcslen(szLogMessage)); 105 | return; 106 | } 107 | 108 | // Function that allows one to specify the log type to be written. 109 | // TRACE, WARN or ERROR types. The corresponding string will be appended to the 110 | // beginning of the log line. 111 | // ** Added a new function instead of changing the vWriteLog() to prevent breaking 112 | // ** existing callers. 113 | void vWriteLogType(int iLogLevel, PLOGGER pLogger, const WCHAR *pszMessageFmt, ...) 114 | { 115 | ASSERT(pszMessageFmt); 116 | ASSERT(iLogLevel >= LOGTYPE_TRACE && iLogLevel <= LOGTYPE_ERROR); 117 | 118 | va_list pArgs; 119 | WCHAR szLogMessage[SLEN_LOGLINE]; 120 | 121 | HRESULT hrReturn = S_OK; 122 | 123 | va_start(pArgs, pszMessageFmt); 124 | hrReturn = StringCchVPrintf(szLogMessage, _countof(szLogMessage), pszMessageFmt, pArgs); 125 | va_end(pArgs); 126 | 127 | if(FAILED(hrReturn)) 128 | { 129 | // todo: 130 | return; 131 | } 132 | 133 | vWriteLogInternal(iLogLevel, pLogger, szLogMessage, wcslen(szLogMessage)); 134 | } 135 | 136 | // Internal function that actually does the writing to log file part 137 | // 138 | static void vWriteLogInternal(int iLogLevel, LOGGER *pLogger, const WCHAR* pszMessage, int nLen) 139 | { 140 | ASSERT(pLogger); 141 | ASSERT(pszMessage); 142 | ASSERT(nLen > 1); 143 | 144 | SYSTEMTIME stCurrentTime; 145 | WCHAR szLogMessage[MAX_LOGLINE]; 146 | 147 | DWORD dwLogChars; 148 | DWORD dwWritten; 149 | 150 | GetLocalTime(&stCurrentTime); 151 | 152 | // todo: read only nLen chars from pszMessage 153 | 154 | // Construct the string to be displayed 155 | switch(iLogLevel) 156 | { 157 | case LOGTYPE_TRACE: 158 | { 159 | swprintf_s(szLogMessage, MAX_LOGLINE, L"[%02d:%02d:%02d.%03d] TRACE: %s\r\n", stCurrentTime.wHour, 160 | stCurrentTime.wMinute, stCurrentTime.wSecond, stCurrentTime.wMilliseconds, pszMessage); 161 | break; 162 | } 163 | 164 | case LOGTYPE_WARN: 165 | { 166 | swprintf_s(szLogMessage, MAX_LOGLINE, L"[%02d:%02d:%02d.%03d] WARN : %s\r\n", stCurrentTime.wHour, 167 | stCurrentTime.wMinute, stCurrentTime.wSecond, stCurrentTime.wMilliseconds, pszMessage); 168 | break; 169 | } 170 | 171 | case LOGTYPE_ERROR: 172 | { 173 | swprintf_s(szLogMessage, MAX_LOGLINE, L"[%02d:%02d:%02d.%03d] ERROR: %s\r\n", stCurrentTime.wHour, 174 | stCurrentTime.wMinute, stCurrentTime.wSecond, stCurrentTime.wMilliseconds, pszMessage); 175 | break; 176 | } 177 | 178 | default: 179 | ASSERT(FALSE); 180 | break; 181 | } 182 | 183 | ASSERT(pLogger->hLogFile); 184 | ASSERT(pLogger->hMutex); 185 | 186 | // Get mutex 187 | if(WaitForSingleObject(pLogger->hMutex, INFINITE) != WAIT_OBJECT_0) 188 | { 189 | // todo: something like an exception. SEH? 190 | return; 191 | } 192 | 193 | dwLogChars = wcslen(szLogMessage) * sizeof(WCHAR); 194 | if(!WriteFile(pLogger->hLogFile, szLogMessage, dwLogChars, &dwWritten, NULL)) 195 | { 196 | // todo: SEH? 197 | } 198 | else if(dwWritten != dwLogChars) 199 | { 200 | // todo: SEH? 201 | } 202 | 203 | ReleaseMutex(pLogger->hMutex); 204 | return; 205 | } 206 | -------------------------------------------------------------------------------- /Debugger/Dasm/Utils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Utils.h" 3 | #include "Defines.h" 4 | 5 | /* Util_fSplitModRMByte() 6 | * Given the ModR/M byte value, returns the individual fields: 7 | * Mod, Reg/Opcode and R/M via pointers to byte variables. 8 | * If any of the __out pointers are NULL, then those fields 9 | * are not computed. 10 | * 11 | * **** This function is also used to spli the SIB byte **** 12 | * ModRM and SIB have the same structure! 13 | * 14 | * Args: 15 | * bModRMValue: BYTE: value of the ModR/M byte. 16 | * pbMod: PBYTE: Address in which to store the Mod field value. 17 | * pbReg: PBYTE: Address in which to store the Reg/Opcode field value. 18 | * pbRM: PBYTE: Address in which to store the R/M field value. 19 | * 20 | * RetVal: 21 | * none 22 | */ 23 | void Util_vSplitModRMByte(BYTE bModRMValue, __out PBYTE pbMod, 24 | __out PBYTE pbReg, __out PBYTE pbRM) 25 | { 26 | // Bits: 7 6 5 4 3 2 1 0 27 | // Field: Mod Reg R/M 28 | if(pbMod) 29 | *pbMod = (bModRMValue & MOD_MASK) >> 6; 30 | if(pbReg) 31 | *pbReg = (bModRMValue & REG_MASK) >> 3; 32 | if(pbRM) 33 | *pbRM = bModRMValue & RM_MASK; 34 | 35 | return; 36 | 37 | }// Util_fSplitModRMByte 38 | 39 | 40 | /* Util_vGetDWBits() 41 | * Given the opcode byte, returns the value of the d and w bits 42 | * of the opcode. If any of the __out pointers are NULL, then 43 | * those fields are not computed. 44 | * 45 | * Args: 46 | * bOpcode: BYTE: value of the opcode byte. 47 | * pbDBit: PBYTE: Address in which to store the D-bit value. 48 | * pbWBit: PBYTE: Address in which to store the W-bit value. 49 | * 50 | * RetVal: 51 | * none 52 | */ 53 | void Util_vGetDWBits(BYTE bOpcode, __out PBYTE pbDBit, __out PBYTE pbWBit) 54 | { 55 | 56 | if(pbDBit) 57 | *pbDBit = (bOpcode & DBIT_MASK) >> 1; 58 | if(pbWBit) 59 | *pbWBit = bOpcode & WBIT_MASK; 60 | 61 | return; 62 | 63 | }// Util_vGetDWBits() 64 | 65 | 66 | /* Util_fIsPrefix() 67 | * Given a byte as argument, tells whether it is a valid prefix or not. 68 | * 69 | * Args: 70 | * bValue: BYTE: value to be checked. 71 | * 72 | * RetVal: 73 | * TRUE/FALSE depending on whether bValue is a prefix or not. 74 | */ 75 | BOOL Util_fIsPrefix(BYTE bValue) 76 | { 77 | switch(bValue) 78 | { 79 | case OPC_PREFIX_SEGOVR_ES: 80 | case OPC_PREFIX_SEGOVR_CS: 81 | case OPC_PREFIX_SEGOVR_SS: 82 | case OPC_PREFIX_SEGOVR_DS: 83 | case OPC_PREFIX_SEGOVR_FS: 84 | case OPC_PREFIX_SEGOVR_GS: 85 | case OPC_PREFIX_OPSIZE: 86 | case OPC_PREFIX_ADSIZE: 87 | case OPC_PREFIX_LOCK: 88 | case OPC_PREFIX_REPNE: 89 | case OPC_PREFIX_REPE: 90 | { 91 | return TRUE; 92 | } 93 | default: 94 | break; 95 | }// switch(bValue) 96 | 97 | return FALSE; 98 | 99 | }// Util_fIsPrefix() 100 | 101 | 102 | // Notes: Under construction 103 | BOOL Util_fDumpIMAGE_IMPORT_DESCRIPTORS(DWORD rva, DWORD dwSize, 104 | PIMAGE_NT_HEADERS pNTHeaders, DWORD dwFileBase) 105 | { 106 | 107 | PIMAGE_SECTION_HEADER pImgSecHeader = NULL; 108 | PIMAGE_IMPORT_DESCRIPTOR pImports = NULL; 109 | 110 | INT iFilePtrRVADelta = 0; 111 | 112 | WCHAR wszTimeStamp[32]; 113 | 114 | // First get the file pointer of the first IMAGE_IMPORT_DESCRIPTOR 115 | if( !CHL_PsGetEnclosingSectionHeader(rva, pNTHeaders, &pImgSecHeader)) 116 | { 117 | wprintf_s(L"fDumpIMAGE_IMPORT_DESCRIPTOR(): Unable to retrieve section header\n"); 118 | wprintf_s(L"rva = 0x%xh, dwSize = 0x%xh, pNTHeaders = %p, dwFileBase = 0x%08xh\n", 119 | rva, dwSize, pNTHeaders, dwFileBase); 120 | return FALSE; 121 | } 122 | 123 | iFilePtrRVADelta = (INT)(pImgSecHeader->PointerToRawData - pImgSecHeader->VirtualAddress); 124 | 125 | // find the Imports within the section 126 | pImports = (PIMAGE_IMPORT_DESCRIPTOR)(rva + iFilePtrRVADelta + dwFileBase); 127 | 128 | wprintf_s(L"\n** IMAGE_IMPORT_DESCRIPTOR **\n"); 129 | 130 | while(pImports->Characteristics != 0 || pImports->FirstThunk != 0 || 131 | pImports->ForwarderChain != 0 || pImports->Name != 0 || 132 | pImports->OriginalFirstThunk != 0 || pImports->TimeDateStamp != 0) 133 | { 134 | wprintf_s(L"Entry:\n"); 135 | wprintf_s(L" Char/OrigFirstThunk: %x\n", pImports->OriginalFirstThunk); 136 | if( pImports->TimeDateStamp != 0 && 137 | _wctime_s(wszTimeStamp, _countof(wszTimeStamp), (time_t*)&pImports->TimeDateStamp) 138 | == 0 ) 139 | { 140 | wprintf_s(L" TimeDateStamp: %xh %s\n", pImports->TimeDateStamp, wszTimeStamp); 141 | } 142 | wprintf_s(L" ForwarderChain: %xh\n", pImports->ForwarderChain); 143 | if(pImports->Name) 144 | wprintf_s(L" Name: %S\n", pImports->Name + iFilePtrRVADelta + dwFileBase); 145 | wprintf_s(L" FirstThunk: %xh\n", pImports->FirstThunk); 146 | wprintf_s(L" IAT:\n"); 147 | 148 | PIMAGE_THUNK_DATA pImgThunkData = (PIMAGE_THUNK_DATA)(pImports->FirstThunk + iFilePtrRVADelta + dwFileBase); 149 | 150 | // Dump the IAT 151 | { 152 | while(pImgThunkData->u1.AddressOfData != 0) 153 | { 154 | wprintf_s(L" -> "); 155 | // If the high bit is set, the bottom 31bits is 156 | // treated as the ordinal value 157 | if(pImgThunkData->u1.AddressOfData & 0x80000000) 158 | wprintf_s(L"Ordinal: %08x\n", IMAGE_ORDINAL(pImgThunkData->u1.Ordinal)); 159 | else 160 | // IMAGE_THUNK_ DATA value is an RVA to the IMAGE_IMPORT_BY_NAME 161 | { 162 | PIMAGE_IMPORT_BY_NAME pImpByName = (PIMAGE_IMPORT_BY_NAME)(pImgThunkData->u1.AddressOfData + 163 | iFilePtrRVADelta + dwFileBase); 164 | wprintf_s(L"Hint: %4u Name: %S\n", pImpByName->Hint, pImpByName->Name); 165 | } 166 | 167 | ++pImgThunkData; 168 | 169 | }// while(pImgThunkData->u1 != 0) 170 | }// IAT block 171 | 172 | wprintf_s(L"\n"); 173 | 174 | ++pImports;// += sizeof(IMAGE_IMPORT_DESCRIPTOR); 175 | 176 | } 177 | 178 | return TRUE; 179 | } 180 | 181 | 182 | void Util_vTwosComplementByte(BYTE chSignedVal, __out PBYTE pchOut) 183 | { 184 | __asm { 185 | push eax 186 | push ebx 187 | xor eax,eax 188 | mov al, chSignedVal 189 | not al 190 | add al, 1 191 | mov ebx, pchOut 192 | mov byte ptr [ebx], al 193 | pop ebx 194 | pop eax 195 | } 196 | 197 | return; 198 | } 199 | 200 | 201 | void Util_vTwosComplementInt(INT iSignedVal, __out PINT piOut) 202 | { 203 | __asm { 204 | push eax 205 | push ebx 206 | xor eax,eax 207 | mov eax, iSignedVal 208 | not eax 209 | add eax, 1 210 | mov ebx, piOut 211 | mov dword ptr [ebx], eax 212 | pop ebx 213 | pop eax 214 | } 215 | 216 | return; 217 | } 218 | -------------------------------------------------------------------------------- /Debugger/Debugger.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {79ad6207-93cc-4ac7-a504-441fca4b2536} 18 | 19 | 20 | {144a647b-00a8-4705-9a44-15b370cb2dbf} 21 | 22 | 23 | {9ccf8d90-3882-4189-a103-4d16307fba65} 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Dasm 65 | 66 | 67 | Dasm 68 | 69 | 70 | Dasm 71 | 72 | 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | Dasm\Header Files 130 | 131 | 132 | Dasm\Header Files 133 | 134 | 135 | Dasm\Header Files 136 | 137 | 138 | Dasm\Header Files 139 | 140 | 141 | Header Files 142 | 143 | 144 | Header Files 145 | 146 | 147 | Libs 148 | 149 | 150 | Libs 151 | 152 | 153 | Libs 154 | 155 | 156 | Libs 157 | 158 | 159 | Libs 160 | 161 | 162 | Libs 163 | 164 | 165 | Libs 166 | 167 | 168 | Libs 169 | 170 | 171 | Libs 172 | 173 | 174 | Libs 175 | 176 | 177 | Libs 178 | 179 | 180 | Libs 181 | 182 | 183 | Libs 184 | 185 | 186 | Libs 187 | 188 | 189 | Libs 190 | 191 | 192 | Libs 193 | 194 | 195 | Libs 196 | 197 | 198 | Libs 199 | 200 | 201 | 202 | 203 | Resource Files 204 | 205 | 206 | -------------------------------------------------------------------------------- /Debugger/Lib/include/Hashtable.h: -------------------------------------------------------------------------------- 1 | 2 | // Hashtable.h 3 | // Hashtable implementation with buckets 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // Unknown history! 7 | // 09/09/14 Refactor to store defs in individual headers. 8 | // 09/12/14 Naming convention modifications 9 | // 10 | 11 | #ifndef _HASHTABLE_H 12 | #define _HASHTABLE_H 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include "Defines.h" 19 | #include "MemFunctions.h" 20 | 21 | // hashtable node 22 | typedef struct _hashTableNode { 23 | BOOL fOccupied; 24 | CHL_KEY chlKey; 25 | CHL_VAL chlVal; 26 | struct _hashTableNode *pnext; 27 | }HT_NODE; 28 | 29 | // Foward declare the iterator struct 30 | struct _hashtableIterator; 31 | 32 | // hashtable itself 33 | typedef struct _hashtable CHL_HTABLE, *PCHL_HTABLE; 34 | struct _hashtable { 35 | CHL_KEYTYPE keyType; // Type information for the hashtable key 36 | CHL_VALTYPE valType; // Type information for the hashtable value 37 | BOOL fValIsInHeap; // Whether value was allocated on heap by client (for CHL_VT_POINTER only) 38 | HT_NODE *phtNodes; // Pointer to hashtable nodes 39 | int nTableSize; // Total number of buckets in the hashtable 40 | 41 | // Access methods 42 | HRESULT (*Destroy)(PCHL_HTABLE phtable); 43 | 44 | HRESULT (*Insert)( 45 | PCHL_HTABLE phtable, 46 | PCVOID pvkey, 47 | int iKeySize, 48 | PVOID pvVal, 49 | int iValSize); 50 | 51 | HRESULT (*Find)( 52 | PCHL_HTABLE phtable, 53 | PCVOID pvkey, 54 | int iKeySize, 55 | PVOID pvVal, 56 | PINT pvalsize, 57 | BOOL fGetPointerOnly); 58 | 59 | HRESULT (*Remove)(PCHL_HTABLE phtable, PCVOID pvkey, int iKeySize); 60 | 61 | HRESULT (*InitIterator)(PCHL_HTABLE phtable, struct _hashtableIterator *pItr); 62 | HRESULT (*GetNext)( 63 | struct _hashtableIterator *pItr, 64 | PCVOID pvKey, 65 | PINT pkeysize, 66 | PVOID pvVal, 67 | PINT pvalsize, 68 | BOOL fGetPointerOnly); 69 | 70 | void (*Dump)(PCHL_HTABLE phtable); 71 | }; 72 | 73 | // Structure that defines the iterator for the hashtable 74 | // Callers can use this to iterate through the hashtable 75 | // and get all (key,value) pairs one-by-one 76 | typedef struct _hashtableIterator { 77 | int opType; 78 | int nCurIndex; // current position in the main bucket 79 | HT_NODE *phtCurNodeInList; // current position in the sibling list 80 | PCHL_HTABLE pMyHashTable; // Pointer to the hashtable to work on 81 | }CHL_HT_ITERATOR; 82 | 83 | // ------------------------------------------- 84 | // Functions exported 85 | 86 | // Creates a hashtable and returns a pointer which can be used for later operations 87 | // on the table. 88 | // Params: 89 | // pHTableOut: Address of pointer where to copy the pointer to the hashtable 90 | // nEstEntries: Estimated number of entries that would be in the table at any given time. 91 | // This is used to determine the initial size of the hashtable. 92 | // keyType: Type of variable that is used as key - a string or a number 93 | // valType: Type of value that is stored - number, string or void(can be anything) 94 | // fValInHeapMem: Set this to true if the value(type is CHL_VT_POINTER) is allocated memory on the heap. 95 | // This indicates the hash table to free it when a table entry is removed. 96 | // 97 | DllExpImp HRESULT CHL_DsCreateHT( 98 | _Inout_ CHL_HTABLE **pHTableOut, 99 | _In_ int nEstEntries, 100 | _In_ CHL_KEYTYPE keyType, 101 | _In_ CHL_VALTYPE valType, 102 | _In_opt_ BOOL fValInHeapMem); 103 | 104 | // Destroy the hashtable by removing all key-value pairs from the hashtable. 105 | // The CHL_HTABLE object itself is also destroyed. 106 | // Params: 107 | // phtable: Pointer to the hashtable object returned by CHL_DsCreateHT function. 108 | // 109 | DllExpImp HRESULT CHL_DsDestroyHT(_In_ CHL_HTABLE *phtable); 110 | 111 | // Inserts a key,value pair into the hash table. If the key already exists, then the value is over-written 112 | // with the new value. If both the key and value already exist, then nothing is changed in the hash table. 113 | // Params: 114 | // phtable: Pointer to the hashtable object returned by CHL_DsCreateHT function. 115 | // pvkey: Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 116 | // iKeySize: Size of the key in bytes. For null-terminated strings, zero may be passed. 117 | // pvVal: Value to be stored. Please see documentation for details. 118 | // iValSize: Size of the value in bytes. For null-terminated strings, zero may be passed. 119 | // 120 | DllExpImp HRESULT CHL_DsInsertHT( 121 | _In_ CHL_HTABLE *phtable, 122 | _In_ PCVOID pvkey, 123 | _In_ int iKeySize, 124 | _In_ PCVOID pvVal, 125 | _In_ int iValSize); 126 | 127 | // Find the specified key in the hash table. 128 | // Params: 129 | // phtable: Pointer to the hashtable object returned by CHL_DsCreateHT function. 130 | // pvkey: Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 131 | // iKeySize: Size of the key in bytes. For null-terminated strings, zero may be passed. 132 | // pvVal: Optional. Pointer to a buffer to receive the value, if found. 133 | // pvalsize: Optional. Size of the value buffer in bytes. If specified size is insufficient, the function 134 | // returns the required size back in this parameter. 135 | // fGetPointerOnly: Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 136 | // If this is TRUE, function returns a pointer to the stored value in the buffer pvVal. 137 | // Otherwise, the full value is copied into the pvVal buffer. 138 | // 139 | DllExpImp HRESULT CHL_DsFindHT( 140 | _In_ CHL_HTABLE *phtable, 141 | _In_ PCVOID pvkey, 142 | _In_ int iKeySize, 143 | _Inout_opt_ PVOID pvVal, 144 | _Inout_opt_ PINT pvalsize, 145 | _In_opt_ BOOL fGetPointerOnly); 146 | 147 | // Deletes the specified key from the hash table. 148 | // Params: 149 | // phtable: Pointer to the hashtable object returned by CHL_DsCreateHT function. 150 | // pvkey: Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 151 | // iKeySize: Size of the key in bytes. For null-terminated strings, zero may be passed. 152 | // 153 | DllExpImp HRESULT CHL_DsRemoveHT(_In_ CHL_HTABLE *phtable, _In_ PCVOID pvkey, _In_ int iKeySize); 154 | 155 | // Initialize the iterator object for use with the specified hashtable. 156 | // Params: 157 | // pItr: Pointer to the iterator object to initialize. 158 | // phtable: Pointer to the hashtable object returned by CHL_DsCreateHT function. 159 | // 160 | DllExpImp HRESULT CHL_DsInitIteratorHT(_In_ PCHL_HTABLE phtable, _Inout_ CHL_HT_ITERATOR *pItr); 161 | 162 | // Get the next element in the hash table using the specified iterator object. 163 | // Params: 164 | // pItr: The iterator object that was initialized by CHL_DsInitIteratorHT. 165 | // pvKey: Optional. Pointer to buffer to receive the key of the next item. 166 | // pKeySize: Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 167 | // returns the required size back in this parameter. 168 | // pvVal: Refer documentation of the CHL_DsFindHT() function. 169 | // pvalsize: Refer documentation of the CHL_DsFindHT() function. 170 | // fGetPointerOnly: Refer documentation of the CHL_DsFindHT() function. 171 | // 172 | DllExpImp HRESULT CHL_DsGetNextHT( 173 | _In_ CHL_HT_ITERATOR *pItr, 174 | _Inout_opt_ PCVOID pvKey, 175 | _Inout_opt_ PINT pkeysize, 176 | _Inout_opt_ PVOID pvVal, 177 | _Inout_opt_ PINT pvalsize, 178 | _In_opt_ BOOL fGetPointerOnly); 179 | 180 | DllExpImp int CHL_DsGetNearestSizeIndexHT(_In_ int maxNumberOfEntries); 181 | DllExpImp void CHL_DsDumpHT(_In_ CHL_HTABLE *phtable); 182 | 183 | // Exposing for unit testing 184 | DllExpImp DWORD _GetKeyHash(_In_ PVOID pvKey, _In_ CHL_KEYTYPE keyType, _In_ int iKeySize, _In_ int iTableNodes); 185 | 186 | #ifdef __cplusplus 187 | } 188 | #endif 189 | 190 | #endif // _HASHTABLE_H 191 | -------------------------------------------------------------------------------- /Debugger/Debugger.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {EDEFC84A-1AD6-4FA6-8042-E198F3172866} 15 | Win32Proj 16 | Debugger 17 | 10.0.15063.0 18 | 19 | 20 | 21 | Application 22 | true 23 | Unicode 24 | v141 25 | 26 | 27 | Application 28 | false 29 | true 30 | Unicode 31 | v141 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);Lib\include 46 | 47 | 48 | false 49 | $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);Lib\include 50 | 51 | 52 | 53 | NotUsing 54 | Level4 55 | Disabled 56 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 57 | Lib\$(Configuration)\ 58 | false 59 | 60 | 61 | Windows 62 | true 63 | false 64 | true 65 | Lib\$(Configuration)\ 66 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Comctl32.lib;Psapi.lib;CHelpLib.lib;%(AdditionalDependencies) 67 | 68 | 69 | xcopy /y $(ProjectDir)Lib\$(Configuration)\CHelpLib.dll $(OutDir) 70 | Copy external DLL to output folder 71 | 72 | 73 | 74 | 75 | Level3 76 | NotUsing 77 | MaxSpeed 78 | true 79 | true 80 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 81 | Lib\$(Configuration)\ 82 | 83 | 84 | Windows 85 | false 86 | true 87 | true 88 | false 89 | Lib\$(Configuration)\ 90 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Comctl32.lib;Psapi.lib;CHelpLib.lib;%(AdditionalDependencies) 91 | 92 | 93 | xcopy /y $(ProjectDir)Lib\$(Configuration)\CHelpLib.dll $(OutDir) 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Debugger/Breakpoint.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\Breakpoint.h" 3 | 4 | extern PLOGGER pstLogger; 5 | 6 | #define OPCODE_BREAKPOINT 0xCC 7 | 8 | static int iGetFirstFreeIdentifier(PINT paiIdentifiers); 9 | static BOOL fBpInsert_Internal(HANDLE hTargetProcess, DWORD dwTargetAddr, __out PBYTE pbOrigCodeByte); 10 | static BOOL fBpRemove_Internal(HANDLE hTargetProcess, DWORD dwTargetAddr, BYTE bOrigCodeByte); 11 | static BOOL fBpCompare(PVOID pvLeft, PVOID pvRight); 12 | 13 | // ** Function Definitions ** 14 | BOOL fBpInitialize(__out PBPLIST *ppstBpList) 15 | { 16 | ASSERT(ppstBpList); 17 | 18 | DWORD dwErrorCode = ERROR_SUCCESS; 19 | PBPLIST pstBpList = NULL; 20 | 21 | if(FAILED(CHL_MmAlloc((void**)&pstBpList, sizeof(BPLIST), &dwErrorCode))) 22 | { 23 | logerror(pstLogger, L"%s(): CHL_MmAlloc() failed %u", __FUNCTIONW__, GetLastError()); 24 | return FALSE; 25 | } 26 | 27 | // pstBpList->aiIdentifiers[] will be zero filled 28 | 29 | if(FAILED(CHL_DsCreateLL(&pstBpList->pstLinkedListBp, CHL_VT_POINTER, MAX_BREAKPOINTS))) 30 | { 31 | logerror(pstLogger, L"%s(): CHL_DsCreateLL() failed %u", __FUNCTIONW__, GetLastError()); 32 | CHL_MmFree((void**)&pstBpList); 33 | return FALSE; 34 | } 35 | 36 | *ppstBpList = pstBpList; 37 | return TRUE; 38 | } 39 | 40 | BOOL fBpTerminate(PBPLIST pBreakpoints) 41 | { 42 | ASSERT(pBreakpoints); 43 | ASSERT(pBreakpoints->pstLinkedListBp); 44 | 45 | BOOL fRetVal = CHL_DsDestroyLL(pBreakpoints->pstLinkedListBp); 46 | 47 | CHL_MmFree((void**)&pBreakpoints); 48 | 49 | return fRetVal; 50 | } 51 | 52 | BOOL fBpInsert(PBPLIST pstBpList, PBPINFO pstBpInfo, PTARGETINFO pstTargetInfo, __out OPTIONAL PINT piBpID) 53 | { 54 | ASSERT(pstBpList); 55 | ASSERT(pstBpInfo); 56 | ASSERT(pstTargetInfo); 57 | 58 | BREAKPOINT stBreakpoint; 59 | int id; 60 | 61 | id = iGetFirstFreeIdentifier(pstBpList->aiIdentifiers); 62 | 63 | // Assume 1-1 mapping between logical and actual breakpoint for now 64 | // TODO: implement n-1 mapping 65 | 66 | stBreakpoint.id = id; 67 | stBreakpoint.bpType = pstBpInfo->iBpType; 68 | 69 | if(pstBpInfo->iBpType & BPTYPE_ASMLEVEL) 70 | { 71 | stBreakpoint.stActualBp.dwAddrInTarget = pstBpInfo->dwTargetAddr; 72 | } 73 | else 74 | { 75 | // TODO: support this 76 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 77 | goto error_return; 78 | } 79 | 80 | stBreakpoint.nReferences = 1; 81 | 82 | // Insert breakpoint into target process 83 | if(!fBpInsert_Internal( 84 | pstTargetInfo->stProcessInfo.hProcess, 85 | pstBpInfo->dwTargetAddr, 86 | &stBreakpoint.stActualBp.bOrigCodeByte)) 87 | { 88 | goto error_return; 89 | } 90 | 91 | stBreakpoint.stActualBp.fResolved = TRUE; 92 | 93 | // Insert into list of breakpoints 94 | if(FAILED(CHL_DsInsertLL(pstBpList->pstLinkedListBp, &stBreakpoint, sizeof(stBreakpoint)))) 95 | { 96 | logerror(pstLogger, L"%s(): CHL_DsInsertLL() failed %u", __FUNCTIONW__, GetLastError()); 97 | 98 | // Remove the inserted breakpoint 99 | if(stBreakpoint.nReferences == 1) 100 | { 101 | fBpRemove_Internal(pstTargetInfo->stProcessInfo.hProcess, pstBpInfo->dwTargetAddr, stBreakpoint.stActualBp.bOrigCodeByte); 102 | } 103 | 104 | goto error_return; 105 | } 106 | 107 | IFPTR_SETVAL(piBpID, id); 108 | return TRUE; 109 | 110 | error_return: 111 | return FALSE; 112 | } 113 | 114 | BOOL fBpRemove(PBPLIST pstBpList, PBPINFO pstBpInfo, PTARGETINFO pstTargetInfo) 115 | { 116 | ASSERT(pstBpList); 117 | ASSERT(pstBpInfo); 118 | 119 | // Assume 1-1 mapping between logical and actual breakpoint for now 120 | // TODO: implement n-1 mapping 121 | 122 | // Only ASM level breakpoints now 123 | // TODO: SOURCE level and using the identifier 124 | 125 | BREAKPOINT stBpToFind; 126 | PBREAKPOINT pstBpFound; 127 | 128 | // TODO: assign bpType as well 129 | stBpToFind.stActualBp.dwAddrInTarget = pstBpInfo->dwTargetAddr; 130 | 131 | int cbOut = sizeof(pstBpFound); 132 | if (FAILED(CHL_DsFindLL(pstBpList->pstLinkedListBp, &stBpToFind, fBpCompare, &pstBpFound, &cbOut, FALSE))) 133 | { 134 | logerror(pstLogger, L"%s(): CHL_DsFindLL() failed %u", __FUNCTIONW__, GetLastError()); 135 | goto error_return; 136 | } 137 | 138 | // Remove from the linked list 139 | if(FAILED(CHL_DsRemoveLL(pstBpList->pstLinkedListBp, &stBpToFind, TRUE, fBpCompare))) 140 | { 141 | logerror(pstLogger, L"%s(): CHL_DsRemoveLL() failed %u", __FUNCTIONW__, GetLastError()); 142 | goto error_return; 143 | } 144 | 145 | // TODO: remove from linked list only after successful removal of actual BP? 146 | 147 | // Replace breakpoint instruction with original opcode 148 | if(pstBpFound->nReferences == 1) 149 | { 150 | dbgwprintf(L"%s(): Removing actual breakpoint at 0x%08x because #references == 1\n", __FUNCTIONW__, pstBpFound->stActualBp.dwAddrInTarget); 151 | if(!fBpRemove_Internal(pstTargetInfo->stProcessInfo.hProcess, pstBpFound->stActualBp.dwAddrInTarget, pstBpFound->stActualBp.bOrigCodeByte)) 152 | { 153 | logerror(pstLogger, L"%s(): fBpRemove_Internal() failed %u", __FUNCTIONW__, GetLastError()); 154 | goto error_return; 155 | } 156 | } 157 | 158 | CHL_MmFree((void**)&pstBpFound); 159 | return TRUE; 160 | 161 | error_return: 162 | IFPTR_FREE(pstBpFound); 163 | return FALSE; 164 | } 165 | 166 | BOOL fBpFind(PBPLIST pstBpList, __inout PBPINFO pstBpInfo, PINT piBpID) 167 | { 168 | ASSERT(pstBpList); 169 | ASSERT(pstBpInfo); 170 | 171 | DBG_UNREFERENCED_PARAMETER(piBpID); 172 | 173 | BREAKPOINT stBpToFind; 174 | PBREAKPOINT pstBpFound = NULL; 175 | 176 | // TODO: suppoprt usage of piBpID also 177 | 178 | // TODO: assign bpType as well 179 | stBpToFind.stActualBp.dwAddrInTarget = pstBpInfo->dwTargetAddr; 180 | 181 | // Find in linked list 182 | int cbOut = sizeof(pstBpFound); 183 | if(FAILED(CHL_DsFindLL(pstBpList->pstLinkedListBp, &stBpToFind, fBpCompare, (void**)&pstBpFound, &cbOut, TRUE))) 184 | { 185 | logerror(pstLogger, L"%s(): CHL_DsFindLL() failed %u", __FUNCTIONW__, GetLastError()); 186 | return FALSE; 187 | } 188 | 189 | // Populate out variable and return TRUE 190 | pstBpInfo->iBpType = pstBpFound->bpType; 191 | pstBpInfo->id = pstBpFound->id; 192 | pstBpInfo->dwTargetAddr = pstBpFound->stActualBp.dwAddrInTarget; 193 | 194 | return TRUE; 195 | } 196 | 197 | static int iGetFirstFreeIdentifier(PINT paiIdentifiers) 198 | { 199 | ASSERT(paiIdentifiers); 200 | 201 | for(int index = 0; index < MAX_BREAKPOINTS; ++index) 202 | { 203 | if(paiIdentifiers[index] == 0) 204 | { 205 | return index + 1; 206 | } 207 | } 208 | 209 | logwarn(pstLogger, L"%s(): No free identifiers!", __FUNCTIONW__); 210 | return -1; 211 | } 212 | 213 | static BOOL fBpInsert_Internal(HANDLE hTargetProcess, DWORD dwTargetAddr, __out PBYTE pbOrigCodeByte) 214 | { 215 | ASSERT(ISVALID_HANDLE(hTargetProcess)); 216 | ASSERT(dwTargetAddr > 0); 217 | ASSERT(pbOrigCodeByte); 218 | 219 | BYTE bOrigCode; 220 | SIZE_T bytesReadWritten; 221 | 222 | BYTE bBreakpointInst = OPCODE_BREAKPOINT; 223 | 224 | // Get the original code byte first 225 | if(!ReadProcessMemory(hTargetProcess, (LPCVOID)dwTargetAddr, &bOrigCode, sizeof(bOrigCode), &bytesReadWritten)) 226 | { 227 | return FALSE; 228 | } 229 | 230 | // TODO: check bytesReadWritten? 231 | 232 | dbgwprintf(L"Original code byte at 0x%08x: 0x%02x\n", dwTargetAddr, bOrigCode); 233 | 234 | // Overwrite with breakpoint instruction 235 | if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwTargetAddr, &bBreakpointInst, sizeof(BYTE), &bytesReadWritten)) 236 | { 237 | return FALSE; 238 | } 239 | 240 | // TODO: check bytesReadWritten? 241 | 242 | *pbOrigCodeByte = bOrigCode; 243 | return TRUE; 244 | } 245 | 246 | static BOOL fBpRemove_Internal(HANDLE hTargetProcess, DWORD dwTargetAddr, BYTE bOrigCodeByte) 247 | { 248 | ASSERT(ISVALID_HANDLE(hTargetProcess)); 249 | ASSERT(dwTargetAddr > 0); 250 | 251 | #ifdef _DEBUG 252 | 253 | // Read the original code byte and assert that it is a 0x03 value 254 | BYTE bOrigCode; 255 | SIZE_T bytesReadWritten; 256 | 257 | // Get the original code byte first 258 | if(!ReadProcessMemory(hTargetProcess, (LPCVOID)dwTargetAddr, &bOrigCode, sizeof(bOrigCode), &bytesReadWritten)) 259 | { 260 | logwarn(pstLogger, L"%s(): ReadProcessMemory() failed %u", __FUNCTIONW__, GetLastError()); 261 | } 262 | else 263 | { 264 | wprintf(L"%s(): Opcode before replacement at 0x%08x: 0x%02x\n", __FUNCTIONW__, dwTargetAddr, bOrigCode); 265 | ASSERT(bOrigCode == OPCODE_BREAKPOINT); 266 | } 267 | 268 | #endif 269 | 270 | if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwTargetAddr, &bOrigCodeByte, sizeof(BYTE), &bytesReadWritten)) 271 | { 272 | return FALSE; 273 | } 274 | 275 | // TODO: check bytesReadWritten? 276 | 277 | return TRUE; 278 | 279 | } 280 | 281 | static BOOL fBpCompare(PVOID pvLeft, PVOID pvRight) 282 | { 283 | ASSERT(pvLeft); 284 | ASSERT(pvRight); 285 | 286 | PBREAKPOINT pstBpLeft = (PBREAKPOINT)pvLeft; 287 | PBREAKPOINT pstBpRight = (PBREAKPOINT)pvRight; 288 | 289 | // Only ASM level comparison now 290 | // TODO: SOURCE level comparison and using the identifier 291 | 292 | return pstBpLeft->stActualBp.dwAddrInTarget == pstBpRight->stActualBp.dwAddrInTarget; 293 | } 294 | -------------------------------------------------------------------------------- /Debugger/Dasm/Dasm.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DASM.h" 3 | 4 | // global variables 5 | DWORD g_dwInputFileType; // set by fBeginFileScan() 6 | BINFILEINFO g_binFileInfo; 7 | 8 | //// ** Controlling program options ** 9 | //// true by default 10 | //BOOL g_fHeaders = TRUE; // NTHeaders, FileHeader, Optional Header 11 | //BOOL g_fDisasm = TRUE; 12 | // 13 | //// false by default 14 | //BOOL g_fExports; 15 | //BOOL g_fImports; 16 | 17 | //int wmain(int argc, WCHAR **argv) 18 | //{ 19 | // 20 | //#ifdef UNIT_TESTS_ONLY 21 | // vRunTests(); 22 | // //DEngine_FPUUnitTest(); 23 | // //DEngine_MMXUnitTest(); 24 | // //DEngine_SSEUnitTest(); 25 | // return 0; 26 | //#else 27 | // 28 | // WCHAR wszFilepath[MAX_PATH+1] = L""; 29 | // WCHAR wszOutFile[MAX_PATH+1] = L""; 30 | // 31 | // HANDLE hFile = NULL, hFileObj = NULL, hFileView = NULL; 32 | // IMAGE_NT_HEADERS *pNTHeaders = NULL; 33 | // DWORD dwCodeSecOffset = 0; 34 | // DWORD dwSizeOfCodeSection = 0; 35 | // 36 | // NCODE_LOCS NNonCodeLocs; 37 | // 38 | // //wprintf_s(L"%d %d %d\n", sizeof(long long), sizeof(INT), sizeof(DWORD)); 39 | // //wprintf_s(L"sizeof(IMAGE_IMPORT_DESCRIPTOR) = %d\n", sizeof(IMAGE_IMPORT_DESCRIPTOR)); 40 | // 41 | // #ifdef NDEBUG 42 | // // Opening statement 43 | // wprintf(L"Shishir's Garage project::DASM v%s, a disassembler for 32bit PE files\ 44 | // \nCoder: Shishir Bhat {shishirb.asm@gmail.com}\ 45 | // \nCopyright: None but don't forget to include my name as a reference in your code/webpage. :)\n\n", DASM_VERSION_STR); 46 | // #endif 47 | // 48 | // /* 49 | // * If no arguments are specified, then prompt user for path to 50 | // * file to disassemble. 51 | // * If one argument is given, then assume that as the file to be 52 | // * disassembled. 53 | // * If there are 2 arguments, then assume the first one as the 54 | // * exe/dll/... file, and the second one as the output file in 55 | // * which we must write the output. 56 | // * 57 | // * todo: No support for output file yet!! 58 | // */ 59 | // //if(argc == 1) 60 | // //{ 61 | // // wprintf_s(L"Enter the path to file: "); 62 | // // wscanf_s(L"%s", wszFilepath); 63 | // //} 64 | // //else if(argc == 2) 65 | // //{ 66 | // // // input file in argv[1] 67 | // // wcscpy_s(wszFilepath, MAX_PATH+1, argv[1]); 68 | // //} 69 | // //else 70 | // //{ 71 | // // wprintf_s(L"usage: %s []\n", argv[0]); 72 | // // return 1; 73 | // //} 74 | // 75 | // //if(!fCmdArgsHandler(argc, argv, wszFilepath, _countof(wszFilepath))) 76 | // //{ 77 | // // wprintf_s(L"main(): Unable to parse command line arguments\n"); 78 | // // wprintf_s(L"usage: %s\n\t[inputFile]\n\t[-exports|-e]\n\t[-imports|-i]\n\t[-headers|-h]\n\t[-disasm|-d]\n", argv[0]); 79 | // // return 1; 80 | // //} 81 | // 82 | // //wprintf_s(L"Using input file: %s\nOutput file: %s\n", wszFilepath, wszOutFile); 83 | // //wprintf_s(L"Using input file: %s\n", wszFilepath); 84 | // 85 | // //if( ! fOpenAndMapFile(wszFilepath, &hFile, &hFileObj, &hFileView) ) 86 | // //{ 87 | // // wprintf_s(L"Error opening input file\n"); 88 | // // return 1; 89 | // //} 90 | // 91 | // wprintf_s(L"********************************\nDisassembling file: %s\n", 92 | // wszFilepath); 93 | // 94 | // __try 95 | // { 96 | // // dump information from headers 97 | // if( ! fBeginFileScan(hFile, hFileObj, hFileView) ) 98 | // { 99 | // wprintf_s(L"main(): fBeginFileScan() error\n"); 100 | // return 1; 101 | // } 102 | // 103 | // //if(g_fDisasm) 104 | // //{ 105 | // // // get pointer to code section 106 | // // if( ! fGetPtrToCode((DWORD)hFileView, g_binFileInfo.pNTHeaders, 107 | // // &dwCodeSecOffset, &dwSizeOfCodeSection, &g_binFileInfo.dwVirtBaseOfCode) ) 108 | // // { 109 | // // wprintf_s(L"Cannot retrieve pointer to code section. Aborting...\n"); 110 | // // return 1; 111 | // // } 112 | // 113 | // // //memset(&NNonCodeLocs, 0, sizeof(NNonCodeLocs)); 114 | // 115 | // // // Check if the IAT is present within the .text section 116 | // // // Doing this will lead to a clearer disassembly 117 | // // 118 | // // //NNonCodeLocs.hFileBase = hFileView; 119 | // 120 | // // // Notes: Under construction 121 | // // // begin disassembly 122 | // // // fDisassembler(&NNonCodeLocs, g_binFileInfo.dwVirtBaseOfCode); 123 | // 124 | // // fDoDisassembly( (DWORD*)dwCodeSecOffset, dwSizeOfCodeSection, 125 | // // g_binFileInfo.dwVirtBaseOfCode ); 126 | // //}// if(g_fDisasm) 127 | // 128 | // return 0; 129 | // } 130 | // __finally 131 | // { 132 | // if(hFile != NULL && hFileObj != NULL && hFileView != NULL) 133 | // fCloseFile(hFile, hFileObj, hFileView); 134 | // } 135 | // 136 | //#endif // UNIT_TESTS_ONLY 137 | // 138 | //}// wmain() 139 | 140 | 141 | // Unit testing of individual functions 142 | void vRunTests() 143 | { 144 | 145 | // Util_vSplitModRMByte() 146 | BYTE bModRM; 147 | BYTE bMod; 148 | BYTE bReg; 149 | BYTE bRM; 150 | 151 | bModRM = 0x7c; // 01 111 100 152 | bMod = bReg = bRM = 0xff; 153 | Util_vSplitModRMByte(bModRM, &bMod, &bReg, &bRM); 154 | if( bMod != 1 || bReg != 7 || bRM != 4) 155 | wprintf_s(L"!FAILED: Util_vSplitModRMByte(): %x, %x, %x, %x\n", 156 | bModRM, bMod, bReg, bRM); 157 | else 158 | wprintf_s(L"*Passed: Util_vSplitModRMByte(): %x, %x, %x, %x\n", 159 | bModRM, bMod, bReg, bRM); 160 | 161 | bModRM = 0xff; // 11 111 111 162 | bMod = bReg = bRM = 0; 163 | Util_vSplitModRMByte(bModRM, &bMod, &bReg, &bRM); 164 | if( bMod != 3 || bReg != 7 || bRM != 7) 165 | wprintf_s(L"!FAILED: Util_vSplitModRMByte(): %x, %x, %x, %x\n", 166 | bModRM, bMod, bReg, bRM); 167 | else 168 | wprintf_s(L"*Passed: Util_vSplitModRMByte(): %x, %x, %x, %x\n", 169 | bModRM, bMod, bReg, bRM); 170 | 171 | // test Util_vGetDWBits() 172 | BYTE bD; 173 | BYTE bW; 174 | 175 | Util_vGetDWBits(0x00, &bD, &bW); 176 | if(bD != 0 || bW != 0) 177 | wprintf_s(L"!FAILED: Util_vGetDWBits(): %x, %x, %x\n", 0x00, bD, bW); 178 | else 179 | wprintf_s(L"*Passed: Util_vGetDWBits(): %x, %x, %x\n", 0x00, bD, bW); 180 | 181 | Util_vGetDWBits(0x03, &bD, &bW); 182 | if(bD != 1 || bW != 1) 183 | wprintf_s(L"!FAILED: Util_vGetDWBits(): %x, %x, %x\n", 0x03, bD, bW); 184 | else 185 | wprintf_s(L"*Passed: Util_vGetDWBits(): %x, %x, %x\n", 0x03, bD, bW); 186 | 187 | Util_vGetDWBits(0x01, &bD, &bW); 188 | if(bD != 0 || bW != 1) 189 | wprintf_s(L"!FAILED: Util_vGetDWBits(): %x, %x, %x\n", 0x01, bD, bW); 190 | else 191 | wprintf_s(L"*Passed: Util_vGetDWBits(): %x, %x, %x\n", 0x01, bD, bW); 192 | 193 | Util_vGetDWBits(0x02, &bD, &bW); 194 | if(bD != 1 || bW != 0) 195 | wprintf_s(L"!FAILED: Util_vGetDWBits(): %x, %x, %x\n", 0x02, bD, bW); 196 | else 197 | wprintf_s(L"*Passed: Util_vGetDWBits(): %x, %x, %x\n", 0x02, bD, bW); 198 | 199 | /* 200 | * Util_vTwosComplementByte() 201 | */ 202 | BYTE ch = 0xe8; 203 | BYTE chCompl; // 2's complement(ch) 204 | Util_vTwosComplementByte(ch, &chCompl); 205 | if(chCompl != 0x18) 206 | wprintf_s(L"!FAILED: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 207 | else 208 | wprintf_s(L"*Passed: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 209 | 210 | ch = 0x00; 211 | Util_vTwosComplementByte(ch, &chCompl); 212 | if(chCompl != 0x00) 213 | wprintf_s(L"!FAILED: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 214 | else 215 | wprintf_s(L"*Passed: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 216 | 217 | ch = 0x7f; 218 | Util_vTwosComplementByte(ch, &chCompl); 219 | if(chCompl != (BYTE)0x81) 220 | wprintf_s(L"!FAILED: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 221 | else 222 | wprintf_s(L"*Passed: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 223 | 224 | ch = 0xff; 225 | Util_vTwosComplementByte(ch, &chCompl); 226 | if(chCompl != 0x01) 227 | wprintf_s(L"!FAILED: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 228 | else 229 | wprintf_s(L"*Passed: Util_vTwosComplementByte(): %x, %x\n", ch, chCompl); 230 | 231 | /* 232 | * Util_vTwosComplementInt() 233 | */ 234 | INT i = 0x002b34e8; 235 | INT iCompl; // 2's complement(ch) 236 | INT iTemp; 237 | 238 | iTemp = ((i ^ 0xffffffff) + 1); 239 | Util_vTwosComplementInt(i, &iCompl); 240 | if(iCompl != iTemp) 241 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 242 | else 243 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 244 | 245 | i = 0x00; 246 | iTemp = ((i ^ 0xffffffff) + 1); 247 | Util_vTwosComplementInt(i, &iCompl); 248 | if(iCompl != iTemp) 249 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 250 | else 251 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 252 | 253 | i = 0x7fffffff; 254 | iTemp = ((i ^ 0xffffffff) + 1); 255 | Util_vTwosComplementInt(i, &iCompl); 256 | if(iCompl != iTemp) 257 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 258 | else 259 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 260 | 261 | i = 0xffffffff; 262 | iTemp = ((i ^ 0xffffffff) + 1); 263 | Util_vTwosComplementInt(i, &iCompl); 264 | if(iCompl != iTemp) 265 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 266 | else 267 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 268 | 269 | i = 0x8b00401b; 270 | iTemp = ((i ^ 0xffffffff) + 1); 271 | Util_vTwosComplementInt(i, &iCompl); 272 | if(iCompl != iTemp) 273 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 274 | else 275 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 276 | 277 | i = 0x80000000; 278 | iTemp = ((i ^ 0xffffffff) + 1); 279 | Util_vTwosComplementInt(i, &iCompl); 280 | if(iCompl != iTemp) 281 | wprintf_s(L"!FAILED: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 282 | else 283 | wprintf_s(L"*Passed: Util_vTwosComplementInt(): %x, %x\n", i, iCompl); 284 | 285 | }// vRunTests() 286 | -------------------------------------------------------------------------------- /Debugger/Lib/include/BinarySearchTree.h: -------------------------------------------------------------------------------- 1 | 2 | // BinarySearchTree.h 3 | // The quintessential data structure in computer science - the binary search tree 4 | // Shishir Bhat (http://www.shishirbhat.com) 5 | // History 6 | // 2016/01/28 Initial version. Create, destroy, insert and traverse. 7 | // 8 | 9 | #ifndef _CHL_BINARY_SEARCHTREE_H 10 | #define _CHL_BINARY_SEARCHTREE_H 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include "Defines.h" 17 | #include "MemFunctions.h" 18 | 19 | typedef enum _bstIerationType { 20 | BstIterationType_PreOrder, 21 | BstIterationType_InOrder, 22 | BstIterationType_PostOrder 23 | } CHL_BstIterationType; 24 | 25 | typedef struct _bstNode { 26 | CHL_KEY chlKey; 27 | CHL_VAL chlVal; 28 | UINT treeSize; // #nodes in the subtree rooted at this node 29 | 30 | struct _bstNode* pLeft; 31 | struct _bstNode* pRight; 32 | //struct _bstNode* pParent; 33 | 34 | } BSTNODE, *PBSTNODE; 35 | 36 | // Foward declare the iterator struct 37 | typedef struct _bstIterator CHL_BST_ITERATOR, *PCHL_BST_ITERATOR; 38 | 39 | // Struct representing the BST object 40 | typedef struct _bstTree CHL_BSTREE, *PCHL_BSTREE; 41 | struct _bstTree { 42 | CHL_KEYTYPE keyType; 43 | CHL_VALTYPE valType; 44 | BOOL fValIsInHeap; 45 | PBSTNODE pRoot; 46 | 47 | CHL_CompareFn fnKeyCompare; 48 | 49 | // Pointers to binary search tree methods 50 | 51 | HRESULT (*Create) 52 | ( 53 | _Out_ PCHL_BSTREE pbst, 54 | _In_ CHL_KEYTYPE keyType, 55 | _In_ CHL_VALTYPE valType, 56 | _In_ CHL_CompareFn pfnKeyCompare, 57 | _In_opt_ BOOL fValInHeapMem 58 | ); 59 | 60 | HRESULT (*Destroy)(_In_ PCHL_BSTREE pbst); 61 | 62 | HRESULT (*Insert) 63 | ( 64 | _In_ PCHL_BSTREE pbst, 65 | _In_ PCVOID pvkey, 66 | _In_ int iKeySize, 67 | _In_ PCVOID pvVal, 68 | _In_ int iValSize 69 | ); 70 | 71 | HRESULT (*Find) 72 | ( 73 | _In_ PCHL_BSTREE pbst, 74 | _In_ PCVOID pvkey, 75 | _In_ int iKeySize, 76 | _Inout_opt_ PVOID pvVal, 77 | _Inout_opt_ PINT pValsize, 78 | _In_opt_ BOOL fGetPointerOnly 79 | ); 80 | 81 | HRESULT (*FindMax) 82 | ( 83 | _In_ PCHL_BSTREE pbst, 84 | _Inout_opt_ PVOID pvKeyOut, 85 | _Inout_opt_ PINT pKeySizeOut, 86 | _In_opt_ BOOL fGetPointerOnly 87 | ); 88 | 89 | HRESULT (*FindMin) 90 | ( 91 | _In_ PCHL_BSTREE pbst, 92 | _Inout_opt_ PVOID pvKeyOut, 93 | _Inout_opt_ PINT pKeySizeOut, 94 | _In_opt_ BOOL fGetPointerOnly 95 | ); 96 | 97 | HRESULT (*FindFloor) 98 | ( 99 | _In_ PCHL_BSTREE pbst, 100 | _In_ PCVOID pvKey, 101 | _In_ int iKeySize, 102 | _Inout_opt_ PVOID pvKeyOut, 103 | _Inout_opt_ PINT pKeySizeOut, 104 | _In_opt_ BOOL fGetPointerOnly 105 | ); 106 | 107 | HRESULT (*FindCeil) 108 | ( 109 | _In_ PCHL_BSTREE pbst, 110 | _In_ PCVOID pvKey, 111 | _In_ int iKeySize, 112 | _Inout_opt_ PVOID pvKeyOut, 113 | _Inout_opt_ PINT pKeySizeOut, 114 | _In_opt_ BOOL fGetPointerOnly 115 | ); 116 | 117 | HRESULT (*InitIterator) 118 | ( 119 | _Out_ PCHL_BST_ITERATOR pItr, 120 | _In_ PCHL_BSTREE pbst, 121 | _In_ CHL_BstIterationType itrType 122 | ); 123 | 124 | HRESULT (*GetNext) 125 | ( 126 | _In_ PCHL_BST_ITERATOR pItr, 127 | _Inout_opt_ PCVOID pvKey, 128 | _Inout_opt_ PINT pKeysize, 129 | _Inout_opt_ PVOID pvVal, 130 | _Inout_opt_ PINT pValSize, 131 | _In_opt_ BOOL fGetPointerOnly 132 | ); 133 | 134 | }; 135 | 136 | // Iterator used to traverse the tree 137 | struct _bstIterator { 138 | CHL_BstIterationType itType; 139 | PCHL_BSTREE pbst; 140 | PBSTNODE pCur; 141 | 142 | // Access methods 143 | 144 | HRESULT(*GetNext) 145 | ( 146 | _In_ PCHL_BST_ITERATOR pItr, 147 | _Inout_opt_ PCVOID pvKey, 148 | _Inout_opt_ PINT pKeysize, 149 | _Inout_opt_ PVOID pvVal, 150 | _Inout_opt_ PINT pValSize, 151 | _In_opt_ BOOL fGetPointerOnly 152 | ); 153 | }; 154 | 155 | 156 | // ------------------------------------------- 157 | // Functions exported 158 | 159 | // Creates a binary search tree and returns a pointer to CHL_BSTREE object 160 | // which can be used for later operations on the tree. 161 | // Params: 162 | // pbst : Pointer to a CHL_BSTREE object to initialize 163 | // keyType : Type of variable that is used as key - refer to definition of CHL_KEYTYPE 164 | // valType : Type of value that is stored - refer to definition of CHL_VALTYPE 165 | // pfnKeyCompare : Pointer to function of type CHL_CompareFn that can compare two keys 166 | // fValInHeapMem : Set this to true if the value (type is CHL_VT_POINTER) is allocated memory on the heap. 167 | // This indicates the tree to free it when an entry is removed. 168 | // 169 | DllExpImp HRESULT CHL_DsCreateBST 170 | ( 171 | _Out_ PCHL_BSTREE pbst, 172 | _In_ CHL_KEYTYPE keyType, 173 | _In_ CHL_VALTYPE valType, 174 | _In_ CHL_CompareFn pfnKeyCompare, 175 | _In_opt_ BOOL fValInHeapMem 176 | ); 177 | 178 | // Destroy the tree by removing all key-value pairs from the tree. 179 | // The CHL_BSTREE object itself is also destroyed. 180 | // Params: 181 | // pbst: Pointer to the BST object returned by CHL_DsCreateBST function. 182 | // 183 | DllExpImp HRESULT CHL_DsDestroyBST(_In_ PCHL_BSTREE pbst); 184 | 185 | // Inserts a key,value pair into the tree. If the key already exists, then the value is over-written 186 | // with the new value. If both the key and value already exist, then nothing is changed in the tree. 187 | // Params: 188 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 189 | // pvkey : Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 190 | // iKeySize: Size of the key in bytes. For null-terminated strings, zero may be passed. 191 | // pvVal : Value to be stored. Please see documentation for details. 192 | // iValSize: Size of the value in bytes. For null-terminated strings, zero may be passed. 193 | // 194 | DllExpImp HRESULT CHL_DsInsertBST 195 | ( 196 | _In_ PCHL_BSTREE pbst, 197 | _In_ PCVOID pvkey, 198 | _In_ int iKeySize, 199 | _In_ PCVOID pvVal, 200 | _In_ int iValSize 201 | ); 202 | 203 | // Find the specified key in the binary search tree. 204 | // Params: 205 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 206 | // pvkey : Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 207 | // iKeySize : Size of the key in bytes. For null-terminated strings, zero may be passed. 208 | // pvVal : Optional. Pointer to a buffer to receive the value, if found. 209 | // pValsize : Optional. Size of the value buffer in bytes. If specified size is insufficient, the function 210 | // returns the required size back in this parameter. 211 | // fGetPointerOnly : Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 212 | // If this is TRUE, function returns a pointer to the stored value in the buffer pvVal. 213 | // Otherwise, the full value is copied into the pvVal buffer. 214 | // 215 | DllExpImp HRESULT CHL_DsFindBST 216 | ( 217 | _In_ PCHL_BSTREE pbst, 218 | _In_ PCVOID pvkey, 219 | _In_ int iKeySize, 220 | _Inout_opt_ PVOID pvVal, 221 | _Inout_opt_ PINT pValsize, 222 | _In_opt_ BOOL fGetPointerOnly 223 | ); 224 | 225 | // Get the maximum key in the binary search tree 226 | // Params: 227 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 228 | // pvKey : Optional. Pointer to buffer to receive the maximum key. 229 | // pKeySize : Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 230 | // returns the required size back in this parameter. 231 | // fGetPointerOnly : Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 232 | // If this is TRUE, function returns a pointer to the stored key in the buffer pvKeyOut. 233 | // Otherwise, the full value is copied into the pKeySizeOut buffer. 234 | // 235 | DllExpImp HRESULT CHL_DsFindMaxBST 236 | ( 237 | _In_ PCHL_BSTREE pbst, 238 | _Inout_opt_ PVOID pvKeyOut, 239 | _Inout_opt_ PINT pKeySizeOut, 240 | _In_opt_ BOOL fGetPointerOnly 241 | ); 242 | 243 | // Get the minimum key in the binary search tree 244 | // Params: 245 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 246 | // pvKey : Optional. Pointer to buffer to receive the minimum key. 247 | // pKeySize : Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 248 | // returns the required size back in this parameter. 249 | // fGetPointerOnly : Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 250 | // If this is TRUE, function returns a pointer to the stored key in the buffer pvKeyOut. 251 | // Otherwise, the full value is copied into the pKeySizeOut buffer. 252 | // 253 | DllExpImp HRESULT CHL_DsFindMinBST 254 | ( 255 | _In_ PCHL_BSTREE pbst, 256 | _Inout_opt_ PVOID pvKey, 257 | _Inout_opt_ PINT pKeysize, 258 | _In_opt_ BOOL fGetPointerOnly 259 | ); 260 | 261 | // Get the floor of specified key in the binary search tree 262 | // Params: 263 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 264 | // pvKey : Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 265 | // iKeySize : Size of the key in bytes. For null-terminated strings, zero may be passed. 266 | // returns the required size back in this parameter. 267 | // pvKeyOut : Optional. Pointer to buffer to receive the floor key, if found. 268 | // pKeySizeOut : Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 269 | // returns the required size back in this parameter. 270 | // fGetPointerOnly : Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 271 | // If this is TRUE, function returns a pointer to the stored key in the buffer pvKeyOut. 272 | // Otherwise, the full value is copied into the pKeySizeOut buffer. 273 | // 274 | DllExpImp HRESULT CHL_DsFindFloorBST 275 | ( 276 | _In_ PCHL_BSTREE pbst, 277 | _In_ PCVOID pvKey, 278 | _In_ int iKeySize, 279 | _Inout_opt_ PVOID pvKeyOut, 280 | _Inout_opt_ PINT pKeySizeOut, 281 | _In_opt_ BOOL fGetPointerOnly 282 | ); 283 | 284 | // Get the ceil of specified key in the binary search tree 285 | // Params: 286 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 287 | // pvKey : Pointer to the key. For primitive types, this is the primitive value casted to a PCVOID. 288 | // iKeySize : Size of the key in bytes. For null-terminated strings, zero may be passed. 289 | // returns the required size back in this parameter. 290 | // pvKeyOut : Optional. Pointer to buffer to receive the ceil key, if found. 291 | // pKeySizeOut : Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 292 | // returns the required size back in this parameter. 293 | // fGetPointerOnly : Applies to value of type CHL_VT_USEROBJECT/CHL_VT_STRING/CHL_VT_WSTRING - 294 | // If this is TRUE, function returns a pointer to the stored key in the buffer pvKeyOut. 295 | // Otherwise, the full value is copied into the pKeySizeOut buffer. 296 | // 297 | DllExpImp HRESULT CHL_DsFindCeilBST 298 | ( 299 | _In_ PCHL_BSTREE pbst, 300 | _In_ PCVOID pvKey, 301 | _In_ int iKeySize, 302 | _Inout_opt_ PVOID pvKeyOut, 303 | _Inout_opt_ PINT pKeySizeOut, 304 | _In_opt_ BOOL fGetPointerOnly 305 | ); 306 | 307 | // Initialize the iterator object for use with the specified BST. 308 | // Params: 309 | // pItr : Pointer to the iterator object to initialize. 310 | // pbst : Pointer to the binary search tree object returned by CHL_DsCreateBST function. 311 | // itrType : Type of iteration to perform (PreOrder/InOrder/PostOrder). 312 | // 313 | DllExpImp HRESULT CHL_DsInitIteratorBST 314 | ( 315 | _Out_ PCHL_BST_ITERATOR pItr, 316 | _In_ PCHL_BSTREE pbst, 317 | _In_ CHL_BstIterationType itrType 318 | ); 319 | 320 | // Get the next entry in the tree using the specified iterator object. 321 | // Params: 322 | // pItr : The iterator object that was initialized by CHL_DsInitIteratorBST. 323 | // pvKey : Optional. Pointer to buffer to receive the key of the next entry. 324 | // pKeySize : Optional. Size of the key buffer in bytes. If specified size is insufficient, the function 325 | // returns the required size back in this parameter. 326 | // pvVal : TODO. 327 | // pvalsize : TODO. 328 | // fGetPointerOnly : TODO. 329 | // 330 | DllExpImp HRESULT CHL_DsGetNextBST 331 | ( 332 | _In_ PCHL_BST_ITERATOR pItr, 333 | _Inout_opt_ PVOID pvKey, 334 | _Inout_opt_ PINT pKeysize, 335 | _Inout_opt_ PVOID pvVal, 336 | _Inout_opt_ PINT pValSize, 337 | _In_opt_ BOOL fGetPointerOnly 338 | ); 339 | 340 | #ifdef __cplusplus 341 | } 342 | #endif 343 | 344 | #endif // _CHL_BINARY_SEARCHTREE_H 345 | -------------------------------------------------------------------------------- /Debugger/UICreator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\UICreator.h" 3 | #include "Inc\DebuggerDP.h" 4 | #include "Inc\SourceHelpers.h" 5 | #include "Defines.h" 6 | 7 | extern HINSTANCE g_hMainInstance; 8 | extern PLOGGER pstLogger; 9 | 10 | static int aiColumnSizePercent_Threads[] = { 12, 12, 52, 12, 12 }; 11 | static int aiColumnSizePercent_Regs[] = { 15, 85 }; 12 | 13 | static WCHAR *aszColumnNames_Threads[] = { L"ThreadId", L"EIPLocation", L"Function", L"Type", L"Priority" }; 14 | static WCHAR *aszColumnNames_Regs[] = { L"Name", L"Value" }; 15 | 16 | struct _FontSelection { 17 | LOGFONT stLogFont; 18 | TEXTMETRIC stTextMetric; 19 | }; 20 | 21 | // File local functions 22 | static BOOL fInsertTabItem(HWND hTab, WCHAR *pszText, __out int *piNewIndex, __out DWORD *pdwErrCode); 23 | BOOL fGetFixedWidthFont(HWND hWindow, HFONT *phFont); 24 | static int CALLBACK EnumFontCallback( 25 | const LOGFONT *lpelfe, 26 | const TEXTMETRIC *lpntme, 27 | DWORD FontType, 28 | LPARAM lParam); 29 | 30 | BOOL fCreateMainTabControl(HWND hMainWnd, __out HWND *phTabControl, DWORD *pdwErrCode) 31 | { 32 | ASSERT(ISVALID_HANDLE(hMainWnd)); 33 | ASSERT(phTabControl); 34 | ASSERT(pdwErrCode); 35 | 36 | RECT rcClientArea; 37 | HWND hTab = NULL; 38 | 39 | if(!GetClientRect(hMainWnd, &rcClientArea)) 40 | { 41 | // todo: log error 42 | goto error_return; 43 | } 44 | 45 | hTab = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD|WS_VISIBLE|WS_BORDER, rcClientArea.left + 5, rcClientArea.top + 5, 46 | rcClientArea.right - 10, rcClientArea.bottom - 10, hMainWnd, (HMENU)IDC_MAINTAB, g_hMainInstance, NULL); 47 | 48 | if(ISNULL(hTab)) 49 | { 50 | // todo: log error 51 | goto error_return; 52 | } 53 | 54 | *phTabControl = hTab; 55 | return TRUE; 56 | 57 | error_return: 58 | *pdwErrCode = GetLastError(); 59 | return FALSE; 60 | } 61 | 62 | BOOL fCreateTabPage(HWND hTab, __out PTABPAGEINFO pstTabPageInfo, __out DWORD *pdwErrCode) 63 | { 64 | ASSERT(ISVALID_HANDLE(hTab)); 65 | ASSERT(pstTabPageInfo); 66 | ASSERT(pdwErrCode); 67 | 68 | RECT rcTabWindow; 69 | RECT rcTabDisplay; 70 | 71 | int iNewIndex = -1; 72 | HWND hEditDisass, hListCStack, hListRegisters, hListThreads, hTabBottom, hEditCommand, hStaticCommand; 73 | 74 | HFONT hFixedFont = NULL; 75 | 76 | // Init all handles to NULL 77 | hEditDisass = hListCStack = hListRegisters = hListThreads = hTabBottom = hEditCommand = hStaticCommand = NULL; 78 | 79 | // Insert a new tab item 80 | if(!fInsertTabItem(hTab, L"Test", &iNewIndex, NULL)) 81 | { 82 | // todo: log 83 | goto error_return; 84 | } 85 | ASSERT(iNewIndex > -1); 86 | 87 | if(!GetWindowRect(hTab, &rcTabWindow)) 88 | { 89 | // todo: log 90 | goto error_return; 91 | } 92 | 93 | CopyRect(&rcTabDisplay, &rcTabWindow); 94 | SendMessage(hTab, TCM_ADJUSTRECT, FALSE, (LPARAM)&rcTabDisplay); 95 | 96 | ScreenToClient(hTab, (LPPOINT)&rcTabDisplay.left); 97 | ScreenToClient(hTab, (LPPOINT)&rcTabDisplay.right); 98 | 99 | // Calculate width for the text static 'Command:' (without quotes) and the edit control 100 | WCHAR szTextCommand[] = L"Command:"; 101 | int iTextWidth, iTextHeight; 102 | 103 | if(FAILED(CHL_GuiGetTextArea(hTab, wcslen(szTextCommand), &iTextWidth, &iTextHeight))) 104 | { 105 | logerror(pstLogger, L"%s(): CHL_GuiGetTextArea() failed %u", GetLastError()); 106 | goto error_return; 107 | } 108 | 109 | int iCursorHeight = GetSystemMetrics(SM_CYCURSOR); 110 | 111 | // Bounding rectangle of the tab page's display area 112 | int x0 = rcTabDisplay.left; 113 | int y0 = rcTabDisplay.top; 114 | int xMax = rcTabDisplay.right; 115 | int yMax = rcTabDisplay.bottom; 116 | 117 | int tabWidth = xMax - x0; 118 | int tabHeight = yMax - y0; 119 | 120 | int liHeight = (tabHeight - iCursorHeight) * 0.33; 121 | 122 | int w50 = tabWidth / 2; // width 1/2 123 | int h75 = tabHeight * 0.75; // height 3/4 124 | int h25 = tabHeight - h75; // height 1/4 125 | 126 | // Get a fixed width font for use in the child controls 127 | if(!fGetFixedWidthFont(hTab, &hFixedFont)) 128 | { 129 | goto error_return; 130 | } 131 | 132 | // Create the disass window 133 | hEditDisass = CreateWindow( 134 | WC_EDIT, 135 | NULL, 136 | WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_READONLY, 137 | x0, 138 | y0, 139 | w50, 140 | h75, 141 | hTab, 142 | (HMENU)IDC_EDIT_DISASS, 143 | g_hMainInstance, 144 | NULL); 145 | 146 | ISNULL_GOTO(hEditDisass, error_return); 147 | SendMessage(hEditDisass, WM_SETFONT, (WPARAM)hFixedFont, FALSE); 148 | 149 | RECT rcTemp; 150 | 151 | // Three list views 152 | hListCStack = CreateWindow( 153 | WC_LISTVIEW, 154 | NULL, 155 | WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, 156 | x0 + w50, 157 | y0, 158 | w50, 159 | liHeight, 160 | hTab, 161 | (HMENU)IDC_LIST_CALLSTACK, 162 | g_hMainInstance, 163 | NULL); 164 | 165 | ISNULL_GOTO(hListCStack, error_return); 166 | GetWindowRect(hListCStack, &rcTemp); 167 | 168 | // TODO: initialize columns 169 | 170 | hListRegisters = CreateWindow( 171 | WC_LISTVIEW, 172 | NULL, 173 | WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, 174 | x0 + w50, 175 | y0 + liHeight, 176 | w50, 177 | liHeight, 178 | hTab, 179 | (HMENU)IDC_LIST_REGISTERS, 180 | g_hMainInstance, 181 | NULL); 182 | 183 | ISNULL_GOTO(hListRegisters, error_return); 184 | 185 | SendMessage(hListRegisters, WM_SETFONT, (WPARAM)hFixedFont, FALSE); 186 | GetWindowRect(hListRegisters, &rcTemp); 187 | 188 | // Initialize columns 189 | if(FAILED(CHL_GuiInitListViewColumns(hListRegisters, aszColumnNames_Regs, NELEMS_ARRAY(aszColumnNames_Regs), aiColumnSizePercent_Regs))) 190 | { 191 | // todo: log error 192 | goto error_return; 193 | } 194 | 195 | hListThreads = CreateWindow( 196 | WC_LISTVIEW, 197 | NULL, 198 | WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, 199 | x0 + w50, 200 | y0 + liHeight + liHeight, 201 | w50, 202 | liHeight, 203 | hTab, 204 | (HMENU)IDC_LIST_THREADS, 205 | g_hMainInstance, 206 | NULL); 207 | 208 | ISNULL_GOTO(hListThreads, error_return); 209 | SendMessage(hListThreads, WM_SETFONT, (WPARAM)hFixedFont, FALSE); 210 | 211 | GetWindowRect(hListThreads, &rcTemp); 212 | 213 | // Initialize columns 214 | if(FAILED(CHL_GuiInitListViewColumns(hListThreads, aszColumnNames_Threads, NELEMS_ARRAY(aszColumnNames_Threads), aiColumnSizePercent_Threads))) 215 | { 216 | // todo: log error 217 | goto error_return; 218 | } 219 | 220 | // Command static and edit controls 221 | hStaticCommand = CreateWindow( 222 | WC_STATIC, 223 | NULL, 224 | WS_CHILD | WS_BORDER | WS_VISIBLE, 225 | x0 + w50, 226 | yMax - iCursorHeight, 227 | iTextWidth, 228 | iCursorHeight, 229 | hTab, 230 | NULL, 231 | g_hMainInstance, 232 | NULL); 233 | 234 | ISNULL_GOTO(hStaticCommand, error_return); 235 | SendMessage(hStaticCommand, WM_SETTEXT, 0, (LPARAM)szTextCommand); 236 | 237 | GetWindowRect(hStaticCommand, &rcTemp); 238 | hEditCommand = CreateWindow( 239 | WC_EDIT, 240 | NULL, 241 | WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT, 242 | x0 + w50 + iTextWidth + 2, 243 | yMax - iCursorHeight, 244 | w50 - iTextWidth - 2, 245 | iCursorHeight, 246 | hTab, 247 | NULL, 248 | g_hMainInstance, 249 | NULL); 250 | 251 | ISNULL_GOTO(hEditCommand, error_return); 252 | 253 | // The bottom tab control 254 | hTabBottom = CreateWindow( 255 | WC_TABCONTROL, 256 | NULL, 257 | WS_CHILD | WS_BORDER | WS_VISIBLE, 258 | x0, 259 | y0 + h75, 260 | w50, 261 | h25, 262 | hTab, 263 | (HMENU)IDC_TAB_BOTTOM, 264 | g_hMainInstance, 265 | NULL); 266 | ISNULL_GOTO(hTabBottom, error_return); 267 | 268 | pstTabPageInfo->hMainTab = hTab; 269 | pstTabPageInfo->hEditDisass = hEditDisass; 270 | pstTabPageInfo->hListCallStack = hListCStack; 271 | pstTabPageInfo->hListRegisters = hListRegisters; 272 | pstTabPageInfo->hListThreads = hListThreads; 273 | pstTabPageInfo->hEditCommand = hEditCommand; 274 | pstTabPageInfo->hStaticCommand = hStaticCommand; 275 | pstTabPageInfo->hTabBottom = hTabBottom; 276 | pstTabPageInfo->iTabIndex = iNewIndex; 277 | pstTabPageInfo->hFixedFont = hFixedFont; 278 | 279 | return TRUE; 280 | 281 | error_return: 282 | SET_ERRORCODE_PTR(pdwErrCode); 283 | ZeroMemory(pstTabPageInfo, sizeof(TABPAGEINFO)); 284 | return FALSE; 285 | } 286 | 287 | BOOL fInsertTabItem(HWND hTab, WCHAR *pszText, __out int *piNewIndex, __out DWORD *pdwErrCode) 288 | { 289 | ASSERT(hTab); 290 | 291 | int nTabs; 292 | int iNewIndex; 293 | TCITEM tcItem; 294 | 295 | // First, get the number of items(pages) already in tab 296 | nTabs = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0); 297 | 298 | // Setup the TCITEM structure 299 | ZeroMemory(&tcItem, sizeof(TCITEM)); 300 | 301 | if(!ISNULL(pszText)) 302 | { 303 | tcItem.mask = TCIF_TEXT; 304 | tcItem.pszText = pszText; 305 | } 306 | 307 | // Insert the item 308 | iNewIndex = SendMessage(hTab, TCM_INSERTITEM, nTabs + 1, (LPARAM)&tcItem); 309 | if(iNewIndex == -1) 310 | { 311 | SET_ERRORCODE_PTR(pdwErrCode); 312 | return FALSE; 313 | } 314 | 315 | if(piNewIndex) 316 | { 317 | *piNewIndex = iNewIndex; 318 | } 319 | return TRUE; 320 | } 321 | 322 | void vDeleteTabPage(HWND hTab, PTABPAGEINFO pstTabPageInfo) 323 | { 324 | ASSERT(ISVALID_HANDLE(hTab)); 325 | ASSERT(pstTabPageInfo); 326 | ASSERT(pstTabPageInfo->iTabIndex >= 0); 327 | 328 | // First, destroy all child windows 329 | DestroyWindow(pstTabPageInfo->hEditDisass); 330 | DestroyWindow(pstTabPageInfo->hListCallStack); 331 | DestroyWindow(pstTabPageInfo->hListRegisters); 332 | DestroyWindow(pstTabPageInfo->hListThreads); 333 | DestroyWindow(pstTabPageInfo->hStaticCommand); 334 | DestroyWindow(pstTabPageInfo->hEditCommand); 335 | DestroyWindow(pstTabPageInfo->hTabBottom); 336 | 337 | // Delete the font GDI object 338 | DeleteObject(pstTabPageInfo->hFixedFont); 339 | 340 | // Remove the tab item 341 | SendMessage(hTab, TCM_DELETEITEM, (int)pstTabPageInfo->iTabIndex, (LPARAM)NULL); 342 | } 343 | 344 | BOOL fSetTabPageText(HWND hTab, int iTabIndex, PCWSTR pszTabText) 345 | { 346 | ASSERT(ISVALID_HANDLE(hTab)); 347 | ASSERT(iTabIndex >= 0); 348 | ASSERT(pszTabText); 349 | 350 | TCITEM stTcItem = {0}; 351 | 352 | stTcItem.mask = TCIF_TEXT; 353 | stTcItem.pszText = (LPWSTR)pszTabText; 354 | 355 | return SendMessage(hTab, TCM_SETITEM, iTabIndex, (LPARAM)&stTcItem); 356 | } 357 | 358 | BOOL fGetFixedWidthFont(HWND hWindow, HFONT *phFont) 359 | { 360 | ASSERT(phFont); 361 | 362 | LOGFONT stLogFont = {0}; 363 | struct _FontSelection stFontSel; 364 | 365 | stLogFont.lfCharSet = ANSI_CHARSET; 366 | stLogFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 367 | HRESULT hr = StringCchCopy(stLogFont.lfFaceName, LF_FACESIZE, L"Consolas"); 368 | if(FAILED(hr)) 369 | { 370 | logerror(pstLogger, L"%s(): StringCchCopy() failed %u.", __FUNCTIONW__, GetLastError()); 371 | return FALSE; 372 | } 373 | 374 | // 1. EnumFontFamilies to enumerate all styles 375 | int ret = EnumFontFamiliesEx(GetDC(hWindow), &stLogFont, EnumFontCallback, (LPARAM)&stFontSel, 0); 376 | if(ret != 0) 377 | { 378 | logerror(pstLogger, L"%s(): Could not select requested font %u.", __FUNCTIONW__, GetLastError()); 379 | return FALSE; 380 | } 381 | 382 | // 2. Populate LOGFONT and call CreateFontIndirect 383 | stFontSel.stLogFont.lfWeight = FW_NORMAL; 384 | stFontSel.stLogFont.lfHeight = -MulDiv(10, GetDeviceCaps(GetDC(hWindow), LOGPIXELSY), 72); 385 | stFontSel.stLogFont.lfWidth = 0; 386 | 387 | HFONT hf = CreateFontIndirect(&stFontSel.stLogFont); 388 | if(!hf) 389 | { 390 | logerror(pstLogger, L"%s(): CreateFontIndirect() failed %u.", __FUNCTIONW__, GetLastError()); 391 | return FALSE; 392 | } 393 | 394 | *phFont = hf; 395 | return TRUE; 396 | } 397 | 398 | int CALLBACK EnumFontCallback( 399 | const LOGFONT *lpelfe, 400 | const TEXTMETRIC *lpntme, 401 | DWORD /*FontType*/, 402 | LPARAM lParam) 403 | { 404 | // Select a normal non-italic style 405 | if(lpelfe->lfWeight == FW_NORMAL && lpelfe->lfItalic != TRUE) 406 | { 407 | memcpy(&((struct _FontSelection*)lParam)->stLogFont, lpelfe, sizeof(*lpelfe)); 408 | memcpy(&((struct _FontSelection*)lParam)->stTextMetric, lpntme, sizeof(*lpntme)); 409 | return 0; 410 | } 411 | return 1; 412 | } 413 | -------------------------------------------------------------------------------- /Debugger/WndProc.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\WndProc.h" 3 | #include "Inc\DebuggerDP.h" 4 | #include "Inc\MenuItems.h" 5 | #include "Inc\GuiManager.h" 6 | #include "Inc\Debug.h" 7 | 8 | extern PLOGGER pstLogger; 9 | extern HINSTANCE g_hMainInstance; 10 | 11 | static HWND hMainTab = NULL; 12 | static HMENU hMainMenu = NULL; 13 | 14 | static int iConInHandle = -1; 15 | static int iConOutHandle = -1; 16 | static int iConErrHandle = -1; 17 | 18 | static int iCurTabIndex = -1; 19 | 20 | // ** File local funtions ** 21 | static BOOL fCreateConsoleWindow(); 22 | 23 | // Menu item handlers 24 | static BOOL fStartDebugSession(HWND hMainWindow, struct _DbgSessionStart *pstSessionInfo, __out DWORD *pdwErrCode); 25 | 26 | static BOOL fSendMessageDebugThread(int iCurIndex, DWORD dwMsgToSend, PGUIDBGCOMM pstCommInfo); 27 | 28 | 29 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 30 | { 31 | DWORD dwError = ERROR_SUCCESS; 32 | 33 | switch(message) 34 | { 35 | case WM_CREATE: 36 | { 37 | vWriteLog(pstLogger, L"WM_CREATE"); 38 | 39 | #if _DEBUG 40 | fCreateConsoleWindow(); 41 | #endif 42 | 43 | if(!fCreateMainTabControl(hWnd, &hMainTab, &dwError)) 44 | { 45 | vWriteLog(pstLogger, L"%s(): Cannot create main control: %d", __FUNCTIONW__, dwError); 46 | SendMessage(hWnd, WM_CLOSE, 0, 0); 47 | } 48 | else 49 | { 50 | hMainMenu = GetMenu(hWnd); 51 | vMiDebuggerInit(hMainMenu); 52 | } 53 | 54 | if(!fGuiInitialize(&dwError)) 55 | { 56 | logerror(pstLogger, L"%s(): Cannot initialize Gui module: %d", __FUNCTIONW__, dwError); 57 | SendMessage(hWnd, WM_CLOSE, 0, 0); 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | case WM_CLOSE: 64 | { 65 | vWriteLog(pstLogger, L"WM_CLOSE"); 66 | break; 67 | } 68 | 69 | case WM_DESTROY: 70 | { 71 | vWriteLog(pstLogger, L"WM_DESTROY"); 72 | vGuiExit(); 73 | 74 | // Terminate logger only at the very end 75 | vTerminateLogger(pstLogger); 76 | 77 | PostQuitMessage(0); 78 | return 0; 79 | } 80 | 81 | case WM_CTLCOLORSTATIC: 82 | { 83 | break; 84 | } 85 | 86 | case WM_NOTIFY: 87 | { 88 | switch(((LPNMHDR)lParam)->code) 89 | { 90 | case TCN_SELCHANGE: 91 | { 92 | iCurTabIndex = TabCtrl_GetCurSel(hMainTab); 93 | if(iCurTabIndex < 0) 94 | { 95 | logwarn(pstLogger, L"%s() %d: TabCtrl_GetCurSel() failed %u", __FUNCTIONW__, __LINE__, GetLastError()); 96 | } 97 | return 0; 98 | } 99 | } 100 | break; 101 | } 102 | 103 | case WM_KEYDOWN: 104 | { 105 | // Handling Ctrl+Alt+O. I don't know why accelerator does not work 106 | // for this key combination 107 | if((WORD)wParam == 'O') 108 | { 109 | // Handle this key combination only if the menu item is enabled 110 | int iMenuState = GetMenuState(hMainMenu, IDM_DEBUGPROCESS, MF_BYCOMMAND); 111 | 112 | if(iMenuState != -1 && !(iMenuState & (MF_DISABLED|MF_GRAYED))) 113 | { 114 | int ic = GetKeyState(VK_CONTROL); 115 | int ia = GetKeyState(VK_MENU); 116 | 117 | if(ic < 0 && ia < 0) 118 | { 119 | SendMessage(hWnd, WM_COMMAND, IDM_DEBUGPROCESS, NULL); 120 | } 121 | } 122 | } 123 | 124 | // TODO: Ctrl+Alt+Pause is also not working. Keyboard issue? 125 | 126 | break; 127 | } 128 | 129 | case WM_COMMAND: 130 | { 131 | switch(LOWORD(wParam)) 132 | { 133 | case IDM_DEBUGPROGRAM: 134 | { 135 | DBG_SESSIONSTART stSessionInfo; 136 | 137 | // Init struct 138 | ZeroMemory(&stSessionInfo, sizeof(stSessionInfo)); 139 | 140 | DialogBoxParam(g_hMainInstance, MAKEINTRESOURCE(IDD_OPENPROGRAM), hWnd, fGetNewProgramDP, (LPARAM)&stSessionInfo); 141 | if(stSessionInfo.szTargetPath[0] == 0) 142 | { 143 | logwarn(pstLogger, L"%s(): Did not get target path to debug from dialog box. Last error = %u", __FUNCTIONW__, GetLastError()); 144 | } 145 | else 146 | { 147 | fStartDebugSession(hWnd, &stSessionInfo, &dwError); 148 | } 149 | return 0; 150 | } 151 | 152 | case IDM_DEBUGPROCESS: 153 | { 154 | DBG_SESSIONSTART stSessionInfo; 155 | 156 | // Init struct 157 | ZeroMemory(&stSessionInfo, sizeof(stSessionInfo)); 158 | 159 | DialogBoxParam(g_hMainInstance, MAKEINTRESOURCE(IDD_GETPROCID), hWnd, fGetProcIdDP, (LPARAM)&stSessionInfo); 160 | if(stSessionInfo.dwTargetPID == 0) 161 | { 162 | logwarn(pstLogger, L"%s(): Did not get PID to debug from dialog box. Last error = %u", __FUNCTIONW__, GetLastError()); 163 | } 164 | else 165 | { 166 | fStartDebugSession(hWnd, &stSessionInfo, &dwError); 167 | } 168 | return 0; 169 | } 170 | 171 | case IDM_TERMINATETARGET: 172 | { 173 | // TODO: handle error return. show MessageBox? 174 | fSendMessageDebugThread(iCurTabIndex, GD_SESS_TERM, NULL); 175 | return 0; 176 | } 177 | 178 | case IDM_DETACHFROMTARGET: 179 | { 180 | fSendMessageDebugThread(iCurTabIndex, GD_SESS_DETACH, NULL); 181 | return 0; 182 | } 183 | 184 | case IDM_DUMPANDTERMINATETARGET: 185 | { 186 | fSendMessageDebugThread(iCurTabIndex, GD_SESS_DUMPTERM, NULL); 187 | return 0; 188 | } 189 | 190 | case IDM_EXITDEBUGGER: 191 | { 192 | vWriteLog(pstLogger, L"IDM_EXITDEBUGGER"); 193 | 194 | // TODO: detach/terminate from all targets being debugged 195 | 196 | if(!fOnExitDetachTargets()) 197 | { 198 | MessageBox(hWnd, L"Error detaching from targets. See log file.", L"Error", MB_ICONEXCLAMATION|MB_OK); 199 | } 200 | 201 | SendMessage(hWnd, WM_CLOSE, 0, 0); 202 | return 0; 203 | } 204 | 205 | case IDM_CONTINUE: 206 | { 207 | fSendMessageDebugThread(iCurTabIndex, GD_MENU_CONTINUE, NULL); 208 | return 0; 209 | } 210 | 211 | case IDM_STEPINTO: 212 | { 213 | fSendMessageDebugThread(iCurTabIndex, GD_MENU_STEPINTO, NULL); 214 | return 0; 215 | } 216 | 217 | case IDM_BREAKINTOTARGET: 218 | { 219 | logtrace(pstLogger, L"IDM_BREAKINTOTARGET"); 220 | fSendMessageDebugThread(iCurTabIndex, GD_MENU_BREAKALL, NULL); 221 | return 0; 222 | } 223 | 224 | case IDM_SUSPENDALLTHREADS: 225 | { 226 | fSendMessageDebugThread(iCurTabIndex, GD_MENU_SUSPALL, NULL); 227 | return 0; 228 | } 229 | 230 | case IDM_RESUMEALLTHREADS: 231 | { 232 | fSendMessageDebugThread(iCurTabIndex, GD_MENU_RESALL, NULL); 233 | return 0; 234 | } 235 | 236 | }// switch(LOWORD...) 237 | 238 | break; 239 | 240 | }// case WM_COMMAND 241 | 242 | // ****************************** Messages from Debug thread ****************************** 243 | case DG_SESS_TERM: 244 | { 245 | PGUIDBGCOMM pstDbgComm = (PGUIDBGCOMM)lParam; 246 | 247 | ASSERT(pstDbgComm); 248 | 249 | logtrace(pstLogger, L"%s(): DG_SESS_TERM from thread %u", __FUNCTIONW__, pstDbgComm->dwThreadID); 250 | if(!fGuiRemTab((int)wParam, &dwError)) 251 | { 252 | logwarn(pstLogger, L"%s(): fGuiRemTab() failed to remove index %d %u", (int)wParam, dwError); 253 | } 254 | 255 | // Continue even if we failed to remove from hash table (next time we insert, it will simply get overwritten) 256 | vDeleteTabPage(hMainTab, &pstDbgComm->stTabPageInfo); 257 | 258 | FREEIF_GUIDBGCOMM(pstDbgComm); 259 | 260 | return 0; 261 | } 262 | 263 | } 264 | 265 | return DefWindowProc(hWnd, message, wParam, lParam); 266 | } 267 | 268 | static BOOL fStartDebugSession(HWND hMainWindow, struct _DbgSessionStart *pstSessionInfo, __out DWORD *pdwErrCode) 269 | { 270 | ASSERT(ISVALID_HANDLE(hMainWindow)); 271 | ASSERT(pstSessionInfo); 272 | 273 | DWORD dwErrorCode = ERROR_SUCCESS; 274 | WCHAR szLogMessage[SLEN_LOGLINE]; 275 | 276 | HANDLE hEventInitSync = NULL; 277 | WCHAR szEventNameSync[SLEN_EVENTNAMES]; 278 | PDEBUGINFO pDebugInfo = NULL; 279 | 280 | HANDLE hThreadDebug = NULL; 281 | DWORD dwThreadId = 0; 282 | 283 | DWORD dwWaitResult = WAIT_FAILED; 284 | 285 | if(FAILED(CHL_MmAlloc((void**)&pDebugInfo, sizeof(DEBUGINFO), &dwErrorCode))) 286 | { 287 | swprintf_s(szLogMessage, _countof(szLogMessage), L"%s(): CHL_MmAlloc failed: %u", __FUNCTIONW__, dwErrorCode); 288 | vWriteLog(pstLogger, szLogMessage); 289 | goto error_return; 290 | } 291 | 292 | // Debug thread needs to know whether it is debugging a new program or 293 | // an active process 294 | if(pstSessionInfo->fDebuggingActiveProcess) 295 | { 296 | ASSERT(pstSessionInfo->dwTargetPID > 0); 297 | pDebugInfo->fDebuggingActiveProcess = TRUE; 298 | pDebugInfo->dwProcessID = pstSessionInfo->dwTargetPID; 299 | } 300 | else 301 | { 302 | ASSERT(pstSessionInfo->szTargetPath[0] != 0); 303 | wcscpy_s(pDebugInfo->szTargetPath, _countof(pDebugInfo->szTargetPath), pstSessionInfo->szTargetPath); 304 | } 305 | 306 | // Insert new tab page 307 | if(!fCreateTabPage(hMainTab, &pDebugInfo->stTabPageInfo, &dwErrorCode)) 308 | { 309 | swprintf_s(szLogMessage, _countof(szLogMessage), L"%s(): fCreateTabPage failed: %u", __FUNCTIONW__, dwErrorCode); 310 | vWriteLog(pstLogger, szLogMessage); 311 | goto error_return; 312 | } 313 | 314 | iCurTabIndex = pDebugInfo->stTabPageInfo.iTabIndex; 315 | 316 | WCHAR szPIDToDisplay[SLEN_COMMON32]; 317 | 318 | PCWSTR pszTabText = NULL; 319 | 320 | if(pstSessionInfo->fDebuggingActiveProcess) 321 | { 322 | swprintf_s(szPIDToDisplay, _countof(szPIDToDisplay), L"PID: %u", pstSessionInfo->dwTargetPID); 323 | pszTabText = szPIDToDisplay; 324 | } 325 | else 326 | { 327 | pszTabText = CHL_SzGetFilenameFromPath( 328 | pstSessionInfo->szTargetPath, 329 | wcsnlen_s(pstSessionInfo->szTargetPath, _countof(pstSessionInfo->szTargetPath))); 330 | } 331 | 332 | fSetTabPageText(hMainTab, pDebugInfo->stTabPageInfo.iTabIndex, pszTabText); 333 | 334 | // Create the init sync event, not signaled to start with 335 | LoadString(g_hMainInstance, IDS_GUIDBG_SYNC, szEventNameSync, _countof(szEventNameSync)); 336 | hEventInitSync = CreateEvent(NULL, FALSE, FALSE, szEventNameSync); 337 | if(hEventInitSync == NULL) 338 | { 339 | SET_ERRORCODE(dwErrorCode); 340 | vWriteLog(pstLogger, L"%s(): CreateEvent failed: %u %s", __FUNCTIONW__, dwErrorCode, szEventNameSync); 341 | goto error_return; 342 | } 343 | 344 | // Create the debug thread, pass in the required info 345 | pDebugInfo->hMainWindow = hMainWindow; 346 | pDebugInfo->hMainMenu = hMainMenu; 347 | pDebugInfo->fBreakAtMain = pstSessionInfo->fBreakAtMain; 348 | wcscpy_s(pDebugInfo->szInitSyncEvtName, _countof(pDebugInfo->szInitSyncEvtName), szEventNameSync); 349 | 350 | if( (hThreadDebug = CreateThread(NULL, 0, dwDebugThreadEntry, (LPVOID)pDebugInfo, CREATE_SUSPENDED, &dwThreadId)) == NULL ) 351 | { 352 | SET_ERRORCODE(dwErrorCode); 353 | vWriteLog(pstLogger, L"%s(): CreateEvent failed: %u %s", __FUNCTIONW__, dwErrorCode, szEventNameSync); 354 | goto error_return; 355 | } 356 | 357 | // Add into map 358 | if(!fGuiAddTab(iCurTabIndex, dwThreadId, &dwErrorCode)) 359 | { 360 | logerror(pstLogger, L"Could not insert into tab-thread map: %u", dwErrorCode); 361 | TerminateThread(hThreadDebug, 0); // safe to terminate since it is anyway not running 362 | FREE_HANDLE(hThreadDebug); 363 | goto error_return; 364 | } 365 | 366 | // todo: handle return value 367 | ResumeThread(hThreadDebug); 368 | 369 | dwWaitResult = WaitForSingleObject(hEventInitSync, 5000); 370 | if( dwWaitResult != WAIT_OBJECT_0 ) 371 | { 372 | SET_ERRORCODE(dwErrorCode); 373 | // ASSERT(FALSE); 374 | vWriteLog(pstLogger, L"%s(): Debug thread(id: %u) failed to signal init sync event", __FUNCTIONW__, dwThreadId); 375 | // goto error_return; 376 | } 377 | FREE_HANDLE(hEventInitSync); 378 | vWriteLog(pstLogger, L"%s(): Done...", __FUNCTIONW__); 379 | return TRUE; 380 | 381 | error_return: 382 | FREE_HANDLE(hEventInitSync); 383 | IFPTR_FREE(pDebugInfo); 384 | IFPTR_SETVAL(pdwErrCode, dwErrorCode); 385 | // remove the tab page 386 | return FALSE; 387 | } 388 | 389 | static BOOL fSendMessageDebugThread(int iCurIndex, DWORD dwMsgToSend, PGUIDBGCOMM pstCommInfo) 390 | { 391 | ASSERT(iCurIndex >= 0); 392 | ASSERT(dwMsgToSend >= CUSTOM_GDEVENT_START && dwMsgToSend <= CUSTOM_GDEVENT_END); 393 | 394 | DWORD dwError; 395 | DWORD dwThreadId; 396 | 397 | DBG_UNREFERENCED_PARAMETER(pstCommInfo); 398 | 399 | if(!fGuiFindTab(iCurTabIndex, &dwThreadId, &dwError)) 400 | { 401 | logerror(pstLogger, L"Cannot find thread ID for tab index %d", iCurTabIndex); 402 | return FALSE; 403 | } 404 | 405 | return PostThreadMessage(dwThreadId, dwMsgToSend, 0, NULL); 406 | } 407 | 408 | static BOOL fCreateConsoleWindow() 409 | { 410 | BOOL fError = TRUE; 411 | 412 | __try 413 | { 414 | if(!AllocConsole()) 415 | { 416 | logerror(pstLogger, L"Could not allocate new console: %d", GetLastError()); 417 | } 418 | else 419 | { 420 | // Thanks to: http://dslweb.nwnexus.com/~ast/dload/guicon.htm and MSDN 421 | FILE *fp = NULL; 422 | HANDLE hInputHandle = GetStdHandle(STD_INPUT_HANDLE); 423 | HANDLE hOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE); 424 | HANDLE hErrorHandle = GetStdHandle(STD_ERROR_HANDLE); 425 | 426 | if(hInputHandle == INVALID_HANDLE_VALUE || hOutputHandle == INVALID_HANDLE_VALUE || 427 | hErrorHandle == INVALID_HANDLE_VALUE) 428 | { 429 | __leave; 430 | } 431 | 432 | if( (iConInHandle = _open_osfhandle((intptr_t)hInputHandle, _O_RDONLY|_O_TEXT)) == -1 ) 433 | __leave; 434 | 435 | fp = _fdopen( iConInHandle, "r" ); 436 | *stdin = *fp; 437 | 438 | if( (iConOutHandle = _open_osfhandle((intptr_t)hOutputHandle, _O_APPEND|_O_TEXT)) == -1 ) 439 | __leave; 440 | 441 | fp = _fdopen( iConOutHandle, "w+" ); 442 | *stdout = *fp; 443 | 444 | if( (iConErrHandle = _open_osfhandle((intptr_t)hErrorHandle, _O_APPEND|_O_TEXT)) == -1 ) 445 | __leave; 446 | 447 | fp = _fdopen( iConErrHandle, "w+" ); 448 | *stderr = *fp; 449 | 450 | fError = FALSE; 451 | } 452 | } 453 | __finally 454 | { 455 | if(fError) 456 | { 457 | if(iConInHandle != -1) { _close(iConInHandle); iConInHandle = -1; } 458 | if(iConOutHandle != -1) { _close(iConOutHandle); iConOutHandle = -1; } 459 | if(iConErrHandle != -1) { _close(iConErrHandle); iConErrHandle = -1; } 460 | FreeConsole(); 461 | } 462 | } 463 | 464 | return !fError; 465 | } 466 | -------------------------------------------------------------------------------- /Debugger/GuiManager.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Inc\GuiManager.h" 3 | #include "Inc\WndProc.h" 4 | 5 | extern PLOGGER pstLogger; 6 | 7 | static CHL_HTABLE *pTabThreadMap = NULL; 8 | 9 | // File local functions 10 | static BOOL fDisplayActiveProcesses(HWND hProcIDList, DWORD **paProcIDs, DWORD *pnProcIDs, DWORD *pnItemsShown); 11 | 12 | BOOL fGuiInitialize(__out DWORD *pdwErrCode) 13 | { 14 | DBG_UNREFERENCED_PARAMETER(pdwErrCode); 15 | 16 | if(pTabThreadMap) 17 | { 18 | CHL_DsDestroyHT(pTabThreadMap); 19 | } 20 | 21 | if(FAILED(CHL_DsCreateHT(&pTabThreadMap, CHL_DsGetNearestSizeIndexHT(5), CHL_KT_UINT32, CHL_VT_UINT32, FALSE))) 22 | { 23 | vWriteLog(pstLogger, L"fGuiInitialize(): Cannot create tab thread map"); 24 | goto error_return; 25 | } 26 | 27 | ASSERT(pTabThreadMap); 28 | return TRUE; 29 | 30 | error_return: 31 | return FALSE; 32 | } 33 | 34 | void vGuiExit() 35 | { 36 | if(pTabThreadMap) 37 | { 38 | CHL_DsDestroyHT(pTabThreadMap); 39 | } 40 | } 41 | 42 | BOOL fGuiAddTab(int tabIndex, DWORD threadId, __out DWORD *pdwErrCode) 43 | { 44 | ASSERT(pTabThreadMap); 45 | ASSERT(tabIndex >= 0); 46 | 47 | DBG_UNREFERENCED_PARAMETER(pdwErrCode); 48 | 49 | #ifdef _DEBUG 50 | WCHAR szDbgMessage[SLEN_LOGLINE]; 51 | swprintf_s(szDbgMessage, _countof(szDbgMessage), L"fGuiAddTab(): %d %u", tabIndex, threadId); 52 | vWriteLog(pstLogger, szDbgMessage); 53 | #endif 54 | 55 | return SUCCEEDED(CHL_DsInsertHT(pTabThreadMap, (PCVOID)tabIndex, sizeof(tabIndex), (PCVOID)threadId, sizeof(threadId))); 56 | } 57 | 58 | BOOL fGuiRemTab(int tabIndex, __out DWORD *pdwErrCode) 59 | { 60 | ASSERT(pTabThreadMap); 61 | ASSERT(tabIndex >= 0); 62 | 63 | DBG_UNREFERENCED_PARAMETER(pdwErrCode); 64 | 65 | #ifdef _DEBUG 66 | WCHAR szDbgMessage[SLEN_LOGLINE]; 67 | swprintf_s(szDbgMessage, _countof(szDbgMessage), L"fGuiRemTab(): %d", tabIndex); 68 | vWriteLog(pstLogger, szDbgMessage); 69 | #endif 70 | 71 | return CHL_DsRemoveHT(pTabThreadMap, (PCVOID)tabIndex, sizeof(tabIndex)); 72 | } 73 | 74 | BOOL fGuiFindTab(int tabIndex, __out DWORD *pdwThreadId, __out DWORD *pdwErrCode) 75 | { 76 | ASSERT(pTabThreadMap); 77 | ASSERT(tabIndex >= 0); 78 | ASSERT(pdwThreadId); 79 | 80 | DBG_UNREFERENCED_PARAMETER(pdwErrCode); 81 | 82 | DWORD dwThreadId; 83 | int iValSize; 84 | 85 | #ifdef _DEBUG 86 | WCHAR szDbgMessage[SLEN_LOGLINE]; 87 | swprintf_s(szDbgMessage, _countof(szDbgMessage), L"fGuiFindTab(): %d", tabIndex); 88 | vWriteLog(pstLogger, szDbgMessage); 89 | #endif 90 | 91 | iValSize = sizeof(dwThreadId); 92 | if(FAILED(CHL_DsFindHT(pTabThreadMap, (PCVOID)tabIndex, sizeof(tabIndex), &dwThreadId, &iValSize, FALSE))) 93 | return FALSE; 94 | 95 | *pdwThreadId = dwThreadId; 96 | return TRUE; 97 | } 98 | 99 | // Function to be called when main window is exiting and we want to detach from 100 | // any targets we have attached to. 101 | // 102 | BOOL fOnExitDetachTargets() 103 | { 104 | CHL_HT_ITERATOR htItr; 105 | 106 | int iTabIndex, keySize, valSize; 107 | DWORD dwThreadId; 108 | 109 | HANDLE hThread = NULL; 110 | DWORD dwWaitStatus; 111 | 112 | BOOL fRetVal = TRUE; 113 | 114 | GUIDBGCOMM stGuiDbgComm; 115 | 116 | if(FAILED(CHL_DsInitIteratorHT(pTabThreadMap, &htItr))) 117 | { 118 | logerror(pstLogger, L"%s(): CHL_DsInitIteratorHT() failed %u", GetLastError()); 119 | return FALSE; 120 | } 121 | 122 | logtrace(pstLogger, L"%s(): Iterating through tab list...", __FUNCTIONW__); 123 | keySize = sizeof(iTabIndex); 124 | while(SUCCEEDED(CHL_DsGetNextHT(&htItr, &iTabIndex, &keySize, &dwThreadId, &valSize, FALSE))) 125 | { 126 | ASSERT(keySize == sizeof(int) && valSize == sizeof(DWORD)); 127 | 128 | logtrace(pstLogger, L"Retrieved %d %u", iTabIndex, dwThreadId); 129 | 130 | hThread = OpenThread(SYNCHRONIZE, FALSE, dwThreadId); 131 | if(hThread == NULL) 132 | { 133 | fRetVal = FALSE; 134 | 135 | logerror(pstLogger, L"OpenThread() failed %u", GetLastError()); 136 | continue; 137 | } 138 | 139 | stGuiDbgComm.fFreeThis = FALSE; 140 | stGuiDbgComm.GD_fDetachOnDebuggerExit = TRUE; 141 | 142 | // Post message and wait for it to terminate 143 | if(!PostThreadMessage(dwThreadId, GD_SESS_DETACH, 0, (LPARAM)&stGuiDbgComm)) 144 | { 145 | fRetVal = FALSE; 146 | 147 | logerror(pstLogger, L"PostThreadMessage() failed %u", GetLastError()); 148 | 149 | CloseHandle(hThread); 150 | continue; 151 | } 152 | 153 | logtrace(pstLogger, L"Waiting for thread %u to exit", dwThreadId); 154 | dwWaitStatus = WaitForSingleObject(hThread, 5000); 155 | if(dwWaitStatus != WAIT_OBJECT_0) 156 | { 157 | fRetVal = FALSE; 158 | 159 | logwarn(pstLogger, L"Thread %u did not terminate within timeout. Moving on...", dwThreadId); 160 | 161 | // fall through to end of while 162 | } 163 | 164 | CloseHandle(hThread); 165 | } 166 | 167 | return fRetVal; 168 | } 169 | 170 | // fGuiGetOpenFilename() 171 | // Just a wrapper for the GetOpenFileName() API 172 | // 173 | BOOL fGuiGetOpenFilename(HWND hMainWindow, WCHAR *pszFilters, __out WCHAR *pszFilepath, DWORD dwBufSize, __out DWORD *pdwErrCode) 174 | { 175 | ASSERT(ISVALID_HANDLE(hMainWindow)); 176 | ASSERT(pszFilters); 177 | ASSERT(pszFilepath); 178 | 179 | DBG_UNREFERENCED_PARAMETER(pdwErrCode); 180 | 181 | OPENFILENAME ofn; 182 | 183 | DWORD dwErrorCode = ERROR_SUCCESS; 184 | 185 | ZeroMemory(&ofn, sizeof(ofn)); 186 | ofn.lStructSize = sizeof(OPENFILENAME); 187 | ofn.hwndOwner = hMainWindow; 188 | ofn.lpstrFilter = pszFilters; 189 | ofn.nFilterIndex = 1; 190 | 191 | pszFilepath[0] = 0; 192 | ofn.lpstrFile = pszFilepath; 193 | ofn.nMaxFile = dwBufSize; 194 | ofn.Flags = OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_NONETWORKBUTTON; 195 | 196 | if(!GetOpenFileName(&ofn)) 197 | { 198 | dwErrorCode = CommDlgExtendedError(); 199 | goto error_return; 200 | } 201 | return TRUE; 202 | 203 | error_return: 204 | pszFilepath[0] = 0; 205 | IFPTR_SETVAL(pdwErrCode, dwErrorCode); 206 | return FALSE; 207 | } 208 | 209 | // fGetProcIdDP() 210 | // 211 | BOOL CALLBACK fGetProcIdDP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 212 | { 213 | static HWND hProcIDList; 214 | static DWORD *paProcIDs; 215 | static DWORD nProcIDs; 216 | static DWORD nListItems; 217 | 218 | static PDBG_SESSIONSTART pstSessionInfo = NULL; 219 | 220 | static int iSelectedListItem; 221 | LPNMLISTVIEW lpNMListView = NULL; 222 | 223 | switch(message) 224 | { 225 | case WM_INITDIALOG: 226 | { 227 | LVCOLUMN lvColumn = {0}; 228 | 229 | paProcIDs = NULL; 230 | nProcIDs = 0; 231 | iSelectedListItem = -1; 232 | 233 | // We should get the address where to store the PID chosen by user, from main window 234 | ASSERT(lParam); 235 | pstSessionInfo = (PDBG_SESSIONSTART)lParam; 236 | 237 | // Set flag to indicate that we will debug an active process 238 | pstSessionInfo->fDebuggingActiveProcess = TRUE; 239 | 240 | CHL_GuiCenterWindow(hDlg); 241 | 242 | hProcIDList = GetDlgItem(hDlg, IDC_LIST_PROCIDS); 243 | 244 | // List view headers 245 | lvColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; 246 | 247 | // first column 248 | lvColumn.pszText = L"Index"; 249 | lvColumn.cx = 0x30; 250 | SendMessage(hProcIDList, LVM_INSERTCOLUMN, 0, (LPARAM)&lvColumn); 251 | 252 | // second column 253 | lvColumn.pszText = L"Process ID"; 254 | lvColumn.cx = 0x60; 255 | SendMessage(hProcIDList, LVM_INSERTCOLUMN, 1, (LPARAM)&lvColumn); 256 | 257 | // third column 258 | lvColumn.pszText = L"Process Name"; 259 | lvColumn.cx = 0x90; 260 | SendMessage(hProcIDList, LVM_INSERTCOLUMN, 2, (LPARAM)&lvColumn); 261 | 262 | // populate list with active processes' ID 263 | if(!fDisplayActiveProcesses(hProcIDList, &paProcIDs, &nProcIDs, &nListItems)) 264 | { 265 | MessageBox(hDlg, L"Cannot display active processes", L"Error", MB_ICONERROR); 266 | SendMessage(hDlg, WM_CLOSE, 0, 0); 267 | } 268 | 269 | return TRUE; 270 | } 271 | 272 | case WM_COMMAND: 273 | { 274 | // handle command sent from child window controls 275 | switch(LOWORD(wParam)) 276 | { 277 | case IDB_OPENPROC: 278 | { 279 | if(iSelectedListItem < 0 || iSelectedListItem > nListItems) 280 | { 281 | MessageBox(hDlg, L"You did not select a process to debug", L"No Process", MB_ICONMASK); 282 | } 283 | else 284 | { 285 | LVITEM lvSelItem = {0}; 286 | WCHAR wsProcID[11]; 287 | 288 | lvSelItem.iItem = iSelectedListItem; 289 | lvSelItem.iSubItem = 1; 290 | lvSelItem.mask = LVIF_TEXT; 291 | lvSelItem.pszText = wsProcID; 292 | lvSelItem.cchTextMax = _countof(wsProcID); 293 | 294 | if(!SendDlgItemMessage(hDlg, IDC_LIST_PROCIDS, LVM_GETITEM, 0, (LPARAM)&lvSelItem)) 295 | { 296 | MessageBox(hDlg, L"Error retrieving selected process's PID", L"Error", MB_OK); 297 | pstSessionInfo->dwTargetPID = 0; 298 | } 299 | else 300 | { 301 | pstSessionInfo->dwTargetPID = _wtoi(lvSelItem.pszText); 302 | } 303 | 304 | SendMessage(hDlg, WM_CLOSE, 0, 0); 305 | } 306 | return TRUE; 307 | } 308 | 309 | case IDB_REFRESH: 310 | { 311 | iSelectedListItem = -1; 312 | // populate list with active processes' ID 313 | if(!fDisplayActiveProcesses(hProcIDList, &paProcIDs, &nProcIDs, &nListItems)) 314 | { 315 | MessageBox(hDlg, L"Cannot display active processes", L"Error", MB_ICONERROR); 316 | SendMessage(hDlg, WM_CLOSE, 0, 0); 317 | } 318 | return TRUE; 319 | } 320 | 321 | case IDB_CANCEL: 322 | { 323 | SendMessage(hDlg, WM_CLOSE, 0, 0); 324 | return TRUE; 325 | } 326 | } 327 | 328 | break; 329 | 330 | }// WM_COMMAND 331 | 332 | case WM_NOTIFY: 333 | { 334 | switch ( ((LPNMHDR)lParam)->code ) 335 | { 336 | case LVN_ITEMCHANGED: 337 | { 338 | if( (lpNMListView = (LPNMLISTVIEW)lParam) == NULL ) 339 | { 340 | // error 341 | dbgwprintf(L"%s(): LVN_ITEMCHANGED: lParam is NULL\n", __FUNCTIONW__); 342 | return 0; 343 | } 344 | 345 | if( lpNMListView->uNewState & LVIS_SELECTED ) 346 | if( lpNMListView->iItem != -1 ) 347 | iSelectedListItem = lpNMListView->iItem; 348 | 349 | return 0; // actually, no return value is required 350 | } 351 | } 352 | 353 | break; 354 | 355 | }// WM_NOTIFY 356 | 357 | case WM_CLOSE: 358 | { 359 | if(paProcIDs) 360 | { 361 | CHL_MmFree((void**)&paProcIDs); 362 | } 363 | 364 | EndDialog(hDlg, 0); 365 | return TRUE; 366 | } 367 | 368 | } 369 | return FALSE; 370 | }// fGetProcIdDP() 371 | 372 | // fDisplayActiveProcesses() 373 | // 374 | static BOOL fDisplayActiveProcesses(HWND hProcIDList, DWORD **paProcIDs, DWORD *pnProcIDs, DWORD *pnItemsShown) 375 | { 376 | ASSERT(hProcIDList && hProcIDList != INVALID_HANDLE_VALUE); 377 | 378 | DWORD dwBytesReturned = 0; 379 | LVITEM lvItem; 380 | 381 | WCHAR wsIndex[5]; 382 | WCHAR wsProcID[11]; 383 | WCHAR wsProcName[MAX_PATH+1]; 384 | 385 | int iRetVal = 0; 386 | int nItemsShown = -1; 387 | 388 | BOOL fErrorInDisplaying = FALSE; 389 | 390 | if(FAILED(CHL_MmAlloc((void**)paProcIDs, 1024*sizeof(DWORD), NULL))) 391 | { 392 | logerror(pstLogger, L"fDisplayActiveProcesses(): mem alloc failed"); 393 | return FALSE; 394 | } 395 | ZeroMemory(*paProcIDs, 1024*sizeof(DWORD)); 396 | 397 | // Clear list view 398 | if(!SendMessage(hProcIDList, LVM_DELETEALLITEMS, 0, 0)) 399 | return FALSE; 400 | 401 | // list processes in the system 402 | if(!EnumProcesses(*paProcIDs, 1024*sizeof(DWORD), &dwBytesReturned)) 403 | { 404 | logerror(pstLogger, L"Failed to enumerate processes in the system. Sorry. %d", GetLastError()); 405 | return FALSE; 406 | } 407 | 408 | logtrace(pstLogger, L"Enumerated %d processes", dwBytesReturned/sizeof(DWORD)); 409 | 410 | *pnProcIDs = dwBytesReturned/sizeof(DWORD); 411 | for(DWORD index = 0; index < dwBytesReturned/sizeof(DWORD); ++index) 412 | { 413 | if(FAILED(CHL_PsGetProcNameFromID((*paProcIDs)[index], wsProcName, _countof(wsProcName)))) 414 | { 415 | dbgwprintf(L"Error reading proc name for %d %d\n", (*paProcIDs)[index], GetLastError()); 416 | logwarn(pstLogger, L"Error reading proc name for %d %d", (*paProcIDs)[index], GetLastError()); 417 | continue; 418 | } 419 | else 420 | { 421 | logtrace(pstLogger, L"%5d %s", (*paProcIDs)[index], wsProcName); 422 | } 423 | 424 | // insert into the list 425 | ZeroMemory(&lvItem, sizeof(lvItem)); 426 | 427 | ++nItemsShown; 428 | 429 | // index 430 | swprintf_s(wsIndex, _countof(wsIndex), L"%d", index); 431 | lvItem.iItem = nItemsShown; 432 | lvItem.mask = LVIF_TEXT; 433 | lvItem.pszText = wsIndex; 434 | lvItem.cchTextMax = wcsnlen_s(wsIndex, _countof(wsIndex)) + 1; 435 | if( (iRetVal = SendMessage(hProcIDList, LVM_INSERTITEM, 0, (LPARAM)&lvItem)) == -1 ) 436 | { 437 | // error 438 | iRetVal = GetLastError(); 439 | logerror(pstLogger, L"fDisplayActiveProcesses(): List insert failed %d", iRetVal); 440 | fErrorInDisplaying = TRUE; 441 | break; 442 | } 443 | 444 | // proc ID 445 | swprintf_s(wsProcID, _countof(wsProcID), L"%d", (*paProcIDs)[index]); 446 | lvItem.iSubItem = 1; 447 | lvItem.mask = LVIF_TEXT; 448 | lvItem.pszText = wsProcID; 449 | lvItem.cchTextMax = wcsnlen_s(wsProcID, _countof(wsProcID)) + 1; 450 | if( (iRetVal = SendMessage(hProcIDList, LVM_SETITEM, 0, (LPARAM)&lvItem)) == -1 ) 451 | { 452 | // error 453 | iRetVal = GetLastError(); 454 | logerror(pstLogger, L"fDisplayActiveProcesses(): List insert failed %d", iRetVal); 455 | fErrorInDisplaying = TRUE; 456 | break; 457 | } 458 | 459 | // proc name 460 | lvItem.iSubItem = 2; 461 | lvItem.mask = LVIF_TEXT; 462 | lvItem.pszText = wsProcName; 463 | lvItem.cchTextMax = wcsnlen_s(wsProcName, _countof(wsProcName)) + 1; 464 | if( (iRetVal = SendMessage(hProcIDList, LVM_SETITEM, 0, (LPARAM)&lvItem)) == -1 ) 465 | { 466 | // error 467 | iRetVal = GetLastError(); 468 | logerror(pstLogger, L"fDisplayActiveProcesses(): List insert failed %d", iRetVal); 469 | fErrorInDisplaying = TRUE; 470 | break; 471 | } 472 | } 473 | 474 | *pnItemsShown = nItemsShown; 475 | return !fErrorInDisplaying; 476 | 477 | }// fDisplayActiveProcesses() 478 | 479 | // fGetNewProgramDP() 480 | // 481 | BOOL CALLBACK fGetNewProgramDP(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 482 | { 483 | static PDBG_SESSIONSTART pstSessionInfo = NULL; 484 | static WCHAR szFilters[] = L"Executables\0*.exe\0\0"; 485 | 486 | HANDLE hFile = NULL; 487 | WCHAR szTargetPath[SLEN_MAXPATH]; 488 | 489 | DWORD dwError = ERROR_SUCCESS; 490 | 491 | switch(message) 492 | { 493 | case WM_INITDIALOG: 494 | { 495 | // We should, from main window, get the address where to store the path of target chosen by user 496 | ASSERT(lParam); 497 | pstSessionInfo = (PDBG_SESSIONSTART)lParam; 498 | ZeroMemory(pstSessionInfo, sizeof(DBG_SESSIONSTART)); 499 | 500 | CHL_GuiCenterWindow(hDlg); 501 | 502 | return TRUE; 503 | } 504 | 505 | case WM_COMMAND: 506 | { 507 | // handle command sent from child window controls 508 | switch(LOWORD(wParam)) 509 | { 510 | case IDC_NP_BROWSE: 511 | { 512 | // Get the path to the target program to be debugged 513 | if(!fGuiGetOpenFilename(hDlg, szFilters, szTargetPath, sizeof(szTargetPath), &dwError)) 514 | { 515 | vWriteLog(pstLogger, L"%s(): fGuiGetOpenFilename failed: %u", __FUNCTIONW__, dwError); 516 | return 0; 517 | } 518 | 519 | // Check if the image file exists and can be read 520 | hFile = CreateFile(szTargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 521 | if(hFile == INVALID_HANDLE_VALUE) 522 | { 523 | MessageBox(hDlg, L"Chosen target path not found or access denied. See log file.", L"Error", MB_ICONEXCLAMATION); 524 | 525 | SET_ERRORCODE(dwError); 526 | vWriteLog(pstLogger, L"%s(): CreateFile failed: %u", __FUNCTIONW__, dwError); 527 | return 0; 528 | } 529 | CloseHandle(hFile); 530 | 531 | // Insert path into the edit control 532 | SendDlgItemMessage(hDlg, IDC_NP_PROGRAMPATH, WM_SETTEXT, 0, (LPARAM)szTargetPath); 533 | 534 | return TRUE; 535 | } 536 | 537 | case IDC_NP_OK: 538 | { 539 | // Get the text from edit control 540 | int nLen = SendDlgItemMessage(hDlg, IDC_NP_PROGRAMPATH, WM_GETTEXTLENGTH, 0, NULL); 541 | 542 | if(nLen < 0) 543 | { 544 | // TODO: show error. log it. 545 | 546 | // Close the dialog 547 | ZeroMemory(pstSessionInfo, sizeof(DBG_SESSIONSTART)); 548 | SendMessage(hDlg, WM_CLOSE, 0, 0); 549 | } 550 | else if(nLen == 0) 551 | { 552 | MessageBox(hDlg, L"Specify path or click Cancel", L"Info", MB_ICONEXCLAMATION); 553 | } 554 | else if(nLen > SLEN_MAXPATH - 1) 555 | { 556 | MessageBox(hDlg, L"Path too long!", L"Error", MB_ICONEXCLAMATION); 557 | logwarn(pstLogger, L"%s(): Target path length too long %d/%d", __FUNCTIONW__, nLen, SLEN_MAXPATH-1); 558 | } 559 | else 560 | { 561 | // Returns number of chars copied 562 | nLen = SendDlgItemMessage(hDlg, IDC_NP_PROGRAMPATH, WM_GETTEXT, _countof(pstSessionInfo->szTargetPath), (LPARAM)pstSessionInfo->szTargetPath); 563 | if(nLen <= 0) 564 | { 565 | MessageBox(hDlg, L"Error reading specified target path. See log file.", L"Error", MB_ICONERROR); 566 | logwarn(pstLogger, L"%s(): WM_GETTEXT failed %u", __FUNCTIONW__, GetLastError()); 567 | } 568 | else 569 | { 570 | // We have copied the path, now get state of the checkbox 571 | if(SendDlgItemMessage(hDlg, IDC_NP_BREAKMAIN, BM_GETCHECK, 0, 0) == BST_CHECKED) 572 | { 573 | pstSessionInfo->fBreakAtMain = TRUE; 574 | } 575 | 576 | SendMessage(hDlg, WM_CLOSE, 0, 0); 577 | } 578 | } 579 | return TRUE; 580 | } 581 | 582 | case IDC_NP_CANCEL: 583 | { 584 | ZeroMemory(pstSessionInfo, sizeof(DBG_SESSIONSTART)); 585 | SendMessage(hDlg, WM_CLOSE, 0, 0); 586 | return TRUE; 587 | } 588 | } 589 | 590 | break; 591 | 592 | }// WM_COMMAND 593 | 594 | case WM_CLOSE: 595 | { 596 | EndDialog(hDlg, 0); 597 | return TRUE; 598 | } 599 | 600 | } 601 | 602 | return FALSE; 603 | } 604 | 605 | BOOL fGuiUpdateThreadsList(HWND hThreadListView, PLV_THREADINFO pstLvThreadInfo, int nItems) 606 | { 607 | ASSERT(ISVALID_HANDLE(hThreadListView)); 608 | ASSERT(pstLvThreadInfo); 609 | ASSERT(nItems > 0 && nItems < 16000); // a reasonable limit, dont'cha think? 610 | 611 | WCHAR szThreadId[SLEN_INT32]; 612 | WCHAR szEipLocation[SLEN_DWORDSTR_HEX]; 613 | WCHAR szFunctionName[SLEN_COMMON128]; 614 | WCHAR szType[SLEN_COMMON32]; 615 | WCHAR szPriority[SLEN_INT32]; 616 | 617 | int index; 618 | WCHAR **ppszStrings; 619 | 620 | // Allocate memory to hold WCHAR pointers to the 5 items to display 621 | if(FAILED(CHL_MmAlloc((void**)&ppszStrings, sizeof(WCHAR*) * LV_THREAD_NUMCOLUMNS, NULL))) 622 | { 623 | return FALSE; 624 | } 625 | 626 | static_assert(LV_THREAD_NUMCOLUMNS == 5, "Expected number of list view columns"); 627 | 628 | ppszStrings[0] = szThreadId; 629 | ppszStrings[1] = szEipLocation; 630 | ppszStrings[2] = szFunctionName; 631 | ppszStrings[3] = szType; 632 | ppszStrings[4] = szPriority; 633 | 634 | // TODO: log failure as error 635 | ListView_DeleteAllItems(hThreadListView); 636 | 637 | for(index = 0; index < nItems; ++index) 638 | { 639 | // Construct the strings 640 | swprintf_s(szThreadId, _countof(szThreadId), L"%u", pstLvThreadInfo[index].dwThreadId); 641 | swprintf_s(szEipLocation, _countof(szEipLocation), L"0x%08x", pstLvThreadInfo[index].dwEIPLocation); 642 | swprintf_s(szFunctionName, _countof(szFunctionName), L"%s", pstLvThreadInfo[index].szFunction); 643 | 644 | ASSERT(pstLvThreadInfo[index].thType == THTYPE_MAIN || pstLvThreadInfo[index].thType == THTYPE_WORKER); 645 | swprintf_s(szType, _countof(szType), L"%s", aszThreadTypes[pstLvThreadInfo[index].thType]); 646 | 647 | swprintf_s(szPriority, _countof(szPriority), L"%d", pstLvThreadInfo[index].iThreadPri); 648 | 649 | // Insert into list view 650 | if(FAILED(CHL_GuiAddListViewRow(hThreadListView, ppszStrings, LV_THREAD_NUMCOLUMNS, NULL))) 651 | { 652 | logerror(pstLogger, L"%s(): CHL_GuiAddListViewRow failed %u", __FUNCTIONW__, GetLastError()); 653 | return FALSE; 654 | } 655 | } 656 | 657 | CHL_MmFree((void**)&ppszStrings); 658 | 659 | return TRUE; 660 | } 661 | 662 | BOOL fGuiUpdateRegistersList(HWND hRegsListView, WCHAR *apszNames[], DWORD *padwValues, int nItems) 663 | { 664 | ASSERT(ISVALID_HANDLE(hRegsListView)); 665 | ASSERT(apszNames); 666 | ASSERT(padwValues); 667 | ASSERT(nItems > 0); 668 | 669 | int index; 670 | WCHAR **ppszStrings; 671 | 672 | WCHAR szName[SLEN_REGISTER_NAME]; 673 | WCHAR szValue[SLEN_DWORDSTR_HEX]; 674 | 675 | // Allocate memory to hold WCHAR pointers to the items to display 676 | if(FAILED(CHL_MmAlloc((void**)&ppszStrings, sizeof(WCHAR*) * LV_REGS_NUMCOLUMNS, NULL))) 677 | { 678 | return FALSE; 679 | } 680 | 681 | static_assert(LV_REGS_NUMCOLUMNS == 2, "Expected number of list view columns"); 682 | 683 | ppszStrings[0] = szName; 684 | ppszStrings[1] = szValue; 685 | 686 | // TODO: log failure as error 687 | ListView_DeleteAllItems(hRegsListView); 688 | 689 | for(index = 0; index < nItems; ++index) 690 | { 691 | swprintf_s(szName, _countof(szName), L"%s", apszNames[index]); 692 | swprintf_s(szValue, _countof(szValue), L"0x%08x", padwValues[index]); 693 | 694 | // Insert into list view 695 | if(FAILED(CHL_GuiAddListViewRow(hRegsListView, ppszStrings, LV_REGS_NUMCOLUMNS, NULL))) 696 | { 697 | logerror(pstLogger, L"%s(): CHL_GuiAddListViewRow failed %u", __FUNCTIONW__, GetLastError()); 698 | return FALSE; 699 | } 700 | } 701 | 702 | CHL_MmFree((void**)&ppszStrings); 703 | 704 | return TRUE; 705 | } 706 | --------------------------------------------------------------------------------