├── SDbgExt ├── SR.cpp ├── WinDbgInterfaces.h ├── stdafx.cpp ├── SDbgExtApi.h ├── dllmain.h ├── SDbgExt_DumpThreadPool.cpp ├── ClrImplExtensions.cpp ├── targetver.h ├── dllmain.cpp ├── _Util.cpp ├── SDbgExt_EnumerateHashtable.cpp ├── GetDelegateMethod.cpp ├── stdafx.h ├── WinDbgExt.cpp ├── IP2MD.cpp ├── SR.h ├── SDbgExtApiExports.h ├── SDbgExt_GetHttpContextFromThread.cpp ├── SDbgExt_EnumSqlConnectionPools.cpp ├── CSDbgBootstrapper.h ├── SDbgExt_EnumHeapObjects.cpp ├── EnumAdaptors.h ├── DictionaryEnumerator.h ├── WinDbgExt.h ├── DumpThreadPoolQueues.cpp ├── DumpMD.cpp ├── SDbgExt_EvaluateExpression.cpp ├── DbgEngMemoryAccess.h ├── SDbgExt.h ├── DumpDictionary.cpp ├── DbgEngCLRDataTarget.h ├── DumpSqlConnectionPools.cpp ├── WinDbgTableFormatter.h ├── SDbgExt_EnumStackObjects.cpp ├── DumpMT.cpp ├── DumpAspNetRequests.cpp ├── SDbgExt.cpp └── CSDbgBootstrapper.cpp ├── SDbgCore ├── inc │ ├── SDbgCore.h │ ├── targetver.h │ ├── SDbgCoreApi.h │ ├── EnumAdaptors.h │ ├── ClrObjectArray.h │ └── ClrObject.h ├── SDbgExt2.cpp ├── stdafx.cpp ├── stdafx.h ├── idl │ ├── CoreApi.idl │ ├── _ClrTypes.idl │ └── _IClrObject.idl ├── SDbgCore.vcxproj.filters └── src │ └── ClrProcess_Heap.cpp ├── lib ├── SDbgCore.dll ├── xclrdata.tlb └── TransformDLL.bat ├── windbg_script.txt ├── SDbgExt2Tests ├── Net4.cpp ├── stdafx.cpp ├── targetver.h ├── ServerThreadTests_x64.cpp ├── stdafx.h ├── RandomTests.cpp ├── MethodDescTests.cpp ├── WorkstationHeapTests_BigHeap.cpp ├── ThreadPoolQueueTests.cpp ├── TestCommon.cpp ├── RequestTests.cpp ├── WorkstationHeapTests.cpp ├── ExpressionTests.cpp ├── ServerThreadTests.cpp ├── ServerHeapTests.cpp ├── StaticFieldTests.cpp ├── TestCommon.h ├── AppDomainTests.cpp ├── FieldTests.cpp ├── SDbgExt2Tests2.vcxproj.filters ├── SqlTests.cpp └── DictionaryTests.cpp ├── README.md ├── SDbgMTests ├── TableWriterTests.cs ├── SqlTests.cs ├── Util.cs ├── ClrProcess.cs ├── ClrProcessTests_ServerIIS.cs ├── Properties │ └── AssemblyInfo.cs └── ObjectProxyTests.cs ├── .gitignore ├── SDbgM ├── WinDbg │ ├── IPluginMethod.cs │ ├── Name2EE.cs │ ├── Stubs.cs │ ├── Threads.cs │ └── DumpMD.cs ├── ClrObjects │ ├── SqlFactory.cs │ ├── HeapSegment.cs │ ├── ObjectInfo.cs │ ├── SqlPoolGroup.cs │ ├── SqlPool.cs │ ├── SqlConnection.cs │ └── CorType.cs ├── Properties │ └── AssemblyInfo.cs ├── SptWrapper │ ├── SptWrapper_Metadata.cs │ └── TableWriter.cs ├── SafeNativeMethods.cs ├── MDbgScriptForm.cs ├── Util │ ├── UsefulGlobals.cs │ └── SuperBitConverter.cs ├── MDbgScriptForm.Designer.cs └── UMThunk.cs └── SDbgExt2.sln /SDbgExt/SR.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /SDbgCore/inc/SDbgCore.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /SDbgExt/WinDbgInterfaces.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/SDbgCore.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveniemitz/SDbgExt2/HEAD/lib/SDbgCore.dll -------------------------------------------------------------------------------- /lib/xclrdata.tlb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveniemitz/SDbgExt2/HEAD/lib/xclrdata.tlb -------------------------------------------------------------------------------- /windbg_script.txt: -------------------------------------------------------------------------------- 1 | ~4s 2 | .load ${$arg1} 3 | $$ !name2ee System.Web.dll System.Web.HttpRuntime 4 | $$ !dumpmd 732c2ee0 5 | !threads 6 | .unload sos -------------------------------------------------------------------------------- /SDbgCore/SDbgExt2.cpp: -------------------------------------------------------------------------------- 1 | // SDbgExt2.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | 7 | int _tmain(int argc, _TCHAR* argv[]) 8 | { 9 | DebugInterfaces 10 | 11 | return 0; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /SDbgExt2Tests/Net4.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | 4 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 5 | 6 | namespace SDbgExt2Tests2 7 | { 8 | TEST_CLASS(Net4) 9 | { 10 | public: 11 | 12 | 13 | }; 14 | } -------------------------------------------------------------------------------- /lib/TransformDLL.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Creating DLL... 3 | tlbimp SDbgCore.tlb /machine:agnostic 4 | 5 | echo ILDASMing... 6 | ildasm SDbgCore.dll /out=SDbgCore.il 7 | 8 | echo Do your thing... 9 | pause 10 | 11 | echo Reassembling... 12 | ilasm /dll SDbgCore.il /output=SDbgCore.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SDbgExt2 / SPT is a wrapper around the IXCLRDataProcess interface. 2 | 3 | SPT is (primarily) a WinDBG add-in. It includes a few useful diagnostic methods: 4 | 5 | - DumpAspNetRequests 6 | - DumpDictionary 7 | - DumpSqlConnectionPools (aka !sqlblame) 8 | - DumpThreadPoolQueues 9 | - FindHttpContext 10 | - GetDelegateMethod 11 | -------------------------------------------------------------------------------- /SDbgExt2Tests/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // SDbgExt2Tests2.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /SDbgExt2Tests/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /SDbgExt2Tests/ServerThreadTests_x64.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | 4 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 5 | 6 | namespace SDbgExt2Tests2 7 | { 8 | TEST_CLASS(ServerThreadTests_x64) 9 | { 10 | public: 11 | 12 | TEST_METHOD(TestMethod1) 13 | { 14 | // TODO: Your test code here 15 | } 16 | 17 | }; 18 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | #define SDBGCORE_USELIB 8 | 9 | #include "targetver.h" 10 | 11 | // Headers for CppUnitTest 12 | #include "CppUnitTest.h" 13 | #include 14 | #include 15 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /SDbgMTests/TableWriterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using SPT.Managed; 6 | 7 | namespace SDbgMTests 8 | { 9 | [TestClass] 10 | public class TableWriterTests 11 | { 12 | [TestMethod] 13 | public void Test_HexPointerFormat() 14 | { 15 | var formatter = new TableWriter.HexAddressFormatProvider(); 16 | 17 | string ret = string.Format(formatter, "{0:p} {1}", (ulong)12345, (int)1234); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SDbgMTests/SqlTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using SPT.Managed; 4 | 5 | namespace SDbgMTests 6 | { 7 | [TestClass] 8 | public class SqlTests 9 | { 10 | private SptWrapper _ext; 11 | 12 | [TestInitialize] 13 | public void Init() 14 | { 15 | _ext = Util.CreateFromDump(@"Q:\spt\Dumps\x86\sql.dmp"); 16 | } 17 | 18 | [TestMethod] 19 | public void DumpSqlConnectionPools_Managed() 20 | { 21 | var ret = _ext.GetSqlPools(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SDbgMTests/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using SPT.Managed; 7 | 8 | namespace SDbgMTests 9 | { 10 | public static class Util 11 | { 12 | public static SptWrapper CreateFromDump(string dumpFile) 13 | { 14 | var bootstrapper = SptWrapper.GetBootstrapper(); 15 | bootstrapper.ConfigureSymbolPath(@"q:\symcache"); 16 | bootstrapper.ConfigureImagePath(@"q:\symcache"); 17 | 18 | return new SptWrapper(bootstrapper.InitFromDump(dumpFile)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SDbgExt2Tests/RandomTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(RandomTests) 10 | { 11 | public: 12 | ADD_BASIC_TEST_INIT 13 | 14 | TEST_METHOD(GetUsefulGlobals) 15 | { 16 | ClrUsefulGlobalsData g; 17 | auto hr = proc->GetUsefulGlobals(&g); 18 | 19 | ASSERT_SOK(hr); 20 | } 21 | 22 | TEST_METHOD(SDbg_GetProcess_RefCounting) 23 | { 24 | for (int a = 0; a < 10; a++) 25 | { 26 | CComPtr proc2; 27 | ext->GetProcess(&proc2); 28 | } 29 | } 30 | 31 | }; 32 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/MethodDescTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(MethodDescTests) 10 | { 11 | public: 12 | ADD_BASIC_TEST_INIT 13 | 14 | TEST_METHOD(FindMethodDesc) 15 | { 16 | CLRDATA_ADDRESS mtAddr = (CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x011539e4, 0x000007fca72c3c10); 17 | CLRDATA_ADDRESS mdAddr = NULL; 18 | 19 | auto hr = p->FindMethodByName(mtAddr, L"SOSRevHelper.TestThreadLocal.Method4()", &mdAddr); 20 | 21 | ASSERT_SOK(hr); 22 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x011539c0, 0x000007fca72c3be0), mdAddr); 23 | } 24 | 25 | }; 26 | } -------------------------------------------------------------------------------- /SDbgCore/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | 19 | #include "stdafx.h" -------------------------------------------------------------------------------- /SDbgExt/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | -------------------------------------------------------------------------------- /SDbgMTests/ClrProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System.Linq; 4 | using System.Diagnostics; 5 | using SPT.Managed; 6 | 7 | namespace SDbgMTests 8 | { 9 | [TestClass] 10 | public class ClrProcessTests_Basic 11 | { 12 | private SptWrapper _proc; 13 | 14 | [TestInitialize] 15 | public void Init() 16 | { 17 | _proc = Util.CreateFromDump(@"Q:\spt\Dumps\x86\iis_request.dmp"); 18 | } 19 | 20 | [TestMethod] 21 | public void EnumHeapSegments_Managed() 22 | { 23 | Stopwatch sw = Stopwatch.StartNew(); 24 | var objs = _proc.GetHeapObjects(); 25 | sw.Stop(); 26 | 27 | Assert.AreEqual(52952, objs.Length); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SDbgExt2Tests/WorkstationHeapTests_BigHeap.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | #ifndef _WIN64 10 | TEST_CLASS(WorkstationHeapTests_MultiSegmentHeap_Traverse) 11 | { 12 | public: 13 | 14 | ADD_TEST_INIT(L"..\\dumps\\x86\\multi_segment_heap.dmp") 15 | 16 | TEST_METHOD(ClrGcHeap_EnumerateObjects_MultiSegment) 17 | { 18 | int n = 0; 19 | 20 | auto cb = [&n](ClrObjectData objData)->BOOL { 21 | n++; 22 | return TRUE; 23 | }; 24 | 25 | CComObject adapt; 26 | adapt.Init(cb); 27 | 28 | ext->EnumHeapObjects(&adapt); 29 | 30 | Assert::AreEqual(1000322, n); 31 | } 32 | 33 | }; 34 | #endif 35 | } -------------------------------------------------------------------------------- /SDbgExt/SDbgExtApi.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 20 | #include "SDbgExtApiExports.h" -------------------------------------------------------------------------------- /SDbgExt2Tests/ThreadPoolQueueTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | #include 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | namespace SDbgExt2Tests2 9 | { 10 | TEST_CLASS(ThreadPoolQueueTests) 11 | { 12 | public: 13 | #ifndef _WIN64 14 | ADD_TEST_INIT(L"..\\Dumps\\x86\\threadpool_queue.dmp") 15 | #else 16 | ADD_TEST_INIT(L"..\\..\\Dumps\\x64\\threadpool.dmp") 17 | #endif 18 | 19 | TEST_METHOD(DumpThreadPool_Baisc) 20 | { 21 | int n = 0; 22 | auto cb = [&n](ThreadPoolWorkItem tpWorkItems)->BOOL { 23 | n++; 24 | return TRUE; 25 | }; 26 | 27 | CComObject adapt; 28 | adapt.Init(cb); 29 | 30 | auto hr = ext->EnumThreadPoolQueues(&adapt); 31 | 32 | ASSERT_SOK(hr); 33 | Assert::AreEqual(BITNESS_CONDITIONAL(0x311, 0x1B), n); 34 | } 35 | }; 36 | } -------------------------------------------------------------------------------- /SDbgExt/dllmain.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include 20 | 21 | class CSDbgCoreModule : public ATL::CAtlDllModuleT 22 | { 23 | 24 | }; 25 | 26 | extern class CSDbgCoreModule _AtlModule; -------------------------------------------------------------------------------- /SDbgExt2Tests/TestCommon.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TestCommon.h" 3 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 4 | 5 | CSDbgTestModule _AtlModule; 6 | 7 | //void SetupTestsFromProcess(DWORD pid, IClrProcess **p) 8 | //{ 9 | // CoInitialize(NULL); 10 | // 11 | // CComPtr chDac; CComPtr chDcma; 12 | // InitRemoteProcess(pid, &chDac, &chDcma); 13 | // 14 | // CreateClrProcess(chDac, chDcma, p); 15 | //} 16 | 17 | void SetupTests(WCHAR *dumpFile, IClrProcess **p, ISDbgExt **ext, IXCLRDataProcess3 **proc) 18 | { 19 | CoInitialize(NULL); 20 | 21 | CComPtr bootstrapper; 22 | CreateBootstrapper(&bootstrapper); 23 | 24 | bootstrapper->ConfigureImagePath(L"Q:\\symcache"); 25 | bootstrapper->ConfigureSymbolPath(L"SRV*q:\\symcache*http://msdl.microsoft.com/download/symbols"); 26 | bootstrapper->InitFromDump(dumpFile, ext); 27 | 28 | (*ext)->GetProcess(p); 29 | (*p)->GetCorDataAccess(proc); 30 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.pdb 10 | *.rc 11 | *.suo 12 | *.sdf 13 | *.exp 14 | *.ipch 15 | *.opensdf 16 | *.obj 17 | *.cache 18 | *.vsp 19 | *.user 20 | *.psess 21 | *.docstates 22 | bin 23 | obj 24 | Debug 25 | Release 26 | x64 27 | 28 | # Packages # 29 | ############ 30 | # it's better to unpack these files and commit the raw source 31 | # git has its own built in compression methods 32 | *.7z 33 | *.dmg 34 | *.gz 35 | *.iso 36 | *.jar 37 | *.rar 38 | *.tar 39 | *.zip 40 | 41 | # Logs and databases # 42 | ###################### 43 | *.log 44 | *.sql 45 | *.sqlite 46 | 47 | # OS generated files # 48 | ###################### 49 | .DS_Store 50 | .DS_Store? 51 | ._* 52 | .Spotlight-V100 53 | .Trashes 54 | Icon? 55 | ehthumbs.db 56 | Thumbs.db 57 | 58 | .svn 59 | *.dmp 60 | TestResults 61 | /SDbgExt2/SDbgCore/CoreApi_h.h 62 | /SDbgExt2/SDbgCore/CoreApi_i.c 63 | /SDbgExt2/lib/*.tlb 64 | /SDbgExt2/lib/*.res -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_DumpThreadPool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include "ThreadPoolEnumerator.h" 21 | 22 | STDMETHODIMP CSDbgExt::EnumThreadPoolQueues(IEnumThreadPoolCallback *tpQueueCb) 23 | { 24 | ThreadPoolEnumerator tp(this, m_proc, tpQueueCb); 25 | return tp.DumpThreadPools(); 26 | } -------------------------------------------------------------------------------- /SDbgExt/ClrImplExtensions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | 21 | #define CLR_DBG_EXT(name) \ 22 | DBG_FUNC(name) { \ 23 | DBG_PREAMBLE \ 24 | UNREFERENCED_PARAMETER(hr); \ 25 | return ExecuteOpCode(&dbg, 1, #name, args); \ 26 | } 27 | 28 | CLR_DBG_EXT(name2ee) 29 | CLR_DBG_EXT(dumpmd) 30 | CLR_DBG_EXT(threads) -------------------------------------------------------------------------------- /SDbgExt2Tests/RequestTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | #ifndef _WIN64 10 | TEST_CLASS(RequestTests) 11 | { 12 | public: 13 | ADD_TEST_INIT(L"..\\dumps\\x86\\iis_request.dmp") 14 | 15 | TEST_METHOD(GetHttpContext) 16 | { 17 | CLRDATA_ADDRESS umThread, mThread; 18 | p->FindThreadByCorThreadId(21, &umThread); 19 | p->GetManagedThreadObject(umThread, &mThread); 20 | 21 | ClrThreadContext ctx; ClrHttpContext httpCtx; 22 | p->GetThreadExecutionContext(mThread, &ctx); 23 | auto hr = ext->GetHttpContextFromThread(ctx, &httpCtx); 24 | 25 | ASSERT_SOK(hr); 26 | Assert::AreEqual((ULONG64)634928680371117848, httpCtx.RequestStartTime.Ticks); 27 | Assert::AreEqual(L"/default.aspx", httpCtx.RequestUrl); 28 | Assert::AreEqual(L"", httpCtx.QueryString); 29 | 30 | SysFreeString(httpCtx.RequestUrl); 31 | SysFreeString(httpCtx.QueryString); 32 | } 33 | 34 | }; 35 | #endif 36 | } -------------------------------------------------------------------------------- /SDbgM/WinDbg/IPluginMethod.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.WinDbg 25 | { 26 | public interface IPluginMethod 27 | { 28 | bool Run(SptWrapper wrapper, string args); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SDbgExt/targetver.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | // Including SDKDDKVer.h defines the highest available Windows platform. 21 | 22 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 23 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 24 | 25 | #include 26 | -------------------------------------------------------------------------------- /SDbgCore/inc/targetver.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | // Including SDKDDKVer.h defines the highest available Windows platform. 21 | 22 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 23 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 24 | 25 | #include 26 | -------------------------------------------------------------------------------- /SDbgCore/stdafx.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "inc\targetver.h" 21 | #define _ATL_DEBUG_INTERFACES 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "inc\SDbgCoreApi.h" 32 | -------------------------------------------------------------------------------- /SDbgExt/dllmain.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | // dllmain.cpp : Defines the entry point for the DLL application. 19 | #include "stdafx.h" 20 | #include "dllmain.h" 21 | 22 | CSDbgCoreModule _AtlModule; 23 | 24 | BOOL APIENTRY DllMain( HINSTANCE hInstance, 25 | DWORD dwReason, 26 | LPVOID lpReserved 27 | ) 28 | { 29 | hInstance; 30 | return _AtlModule.DllMain(dwReason, lpReserved); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /SDbgExt/_Util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include 21 | #include 22 | 23 | std::vector SPT::Util::Tokenize(CStringA str) 24 | { 25 | int curPos = 0; 26 | CStringA resToken; 27 | std::vector tokens; 28 | do 29 | { 30 | resToken = str.Tokenize(" ",curPos).Trim(" "); 31 | if (resToken != "") 32 | { 33 | tokens.push_back(resToken); 34 | } 35 | } while (resToken != ""); 36 | 37 | return tokens; 38 | } -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_EnumerateHashtable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include "DictionaryEnumerator.h" 21 | 22 | STDMETHODIMP CSDbgExt::EnumHashtable(CLRDATA_ADDRESS dctObj, IEnumHashtableCallback *cb) 23 | { 24 | DctEnumerator enumer(m_proc); 25 | return enumer.EnumerateDctEntries(dctObj, cb); 26 | } 27 | 28 | STDMETHODIMP CSDbgExt::FindDctEntryByHash(CLRDATA_ADDRESS dctObj, UINT32 hash, CLRDATA_ADDRESS *entryAddr) 29 | { 30 | DctEnumerator enumer(m_proc); 31 | return enumer.FindDctEntryByHash(dctObj, hash, entryAddr); 32 | } -------------------------------------------------------------------------------- /SDbgMTests/ClrProcessTests_ServerIIS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using SDbgCore; 4 | using SPT.Managed; 5 | 6 | namespace SDbgMTests 7 | { 8 | [TestClass] 9 | public class ClrProcessTests_ServerIIS 10 | { 11 | private SptWrapper _proc; 12 | 13 | [TestInitialize] 14 | public void Init() 15 | { 16 | _proc = Util.CreateFromDump(@"Q:\spt\Dumps\x86\iis_request.dmp"); 17 | } 18 | 19 | [TestMethod] 20 | public void GetStaticFieldValues_Managed() 21 | { 22 | var type = _proc.Proc.FindTypeByName("System.Web.dll", "System.Web.HttpRuntime"); 23 | var field = _proc.Proc.FindFieldByName(type, "_theRuntime"); 24 | var values = _proc.GetStaticFieldValues(field); 25 | 26 | Assert.AreEqual(2, values.Length); 27 | Assert.AreEqual((ulong)0x0000000013fa6300, values[0].Value); 28 | } 29 | 30 | [TestMethod] 31 | public void GetFieldValueString_Managed() 32 | { 33 | //11fa8ca8 34 | var str = _proc.GetFieldValueString(0x11fa8da0, "_pathTranslated"); 35 | Assert.AreEqual(@"Q:\Dev\SOSRevHelper\IISHelper\default.aspx", str); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SDbgM/ClrObjects/SqlFactory.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.ClrObjects 25 | { 26 | public class SqlFactory 27 | { 28 | public SqlFactory(ulong addr) 29 | { 30 | PoolGroups = new List(); 31 | FactoryAddress = addr; 32 | } 33 | 34 | public List PoolGroups { get; private set; } 35 | public ulong FactoryAddress { get; private set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SDbgM/ClrObjects/HeapSegment.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using SDbgCore; 24 | 25 | namespace SPT.Managed 26 | { 27 | public struct HeapSegment 28 | { 29 | private ClrGcHeapSegmentData _data; 30 | 31 | internal HeapSegment(ClrGcHeapSegmentData data) 32 | { 33 | _data = data; 34 | } 35 | 36 | public ulong Segment { get { return _data.Segment; } } 37 | public ClrGcHeapSegmentData Data { get { return _data; } } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SDbgM/ClrObjects/ObjectInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using SDbgCore; 24 | 25 | namespace SPT.Managed.ClrObjects 26 | { 27 | public struct ObjectInfo 28 | { 29 | private readonly ClrObjectData _data; 30 | 31 | public ObjectInfo(ClrObjectData data) 32 | { 33 | _data = data; 34 | } 35 | 36 | public ulong Address { get { return _data.ObjectAddress; } } 37 | public ClrObjectData Data { get { return _data; } } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SDbgExt/GetDelegateMethod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | 21 | DBG_FUNC(getdelegatemethod) 22 | { 23 | DBG_PREAMBLE; 24 | 25 | ULONG64 addr = GetExpression(args); 26 | 27 | ClrDelegateInfo di = {}; 28 | RETURN_IF_FAILED(dbg.Process->GetDelegateInfo(addr, &di)); 29 | 30 | WCHAR buffer[512]; 31 | if (FAILED(dbg.XCLR->GetMethodDescName(di.MethodDesc, ARRAYSIZE(buffer), buffer, NULL))) 32 | { 33 | dwdprintf(dbg.Control, SR::GetDelegateMethod_Error()); 34 | } 35 | else 36 | { 37 | dwdprintf(dbg.Control, SR::GetDelegateMethod_Format(), di.MethodDesc, buffer); 38 | } 39 | 40 | return S_OK; 41 | } -------------------------------------------------------------------------------- /SDbgExt/stdafx.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | // stdafx.h : include file for standard system include files, 19 | // or project specific include files that are used frequently, but 20 | // are changed infrequently 21 | // 22 | 23 | #pragma once 24 | #include "targetver.h" 25 | 26 | #define _ATL_DEBUG_INTERFACES 27 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 28 | // Windows Header Files: 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 37 | #include "SDbgExt.h" 38 | #include "SDbgExtApi.h" -------------------------------------------------------------------------------- /SDbgM/ClrObjects/SqlPoolGroup.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.ClrObjects 25 | { 26 | public class SqlPoolGroup 27 | { 28 | public SqlPoolGroup(string connStr, ulong poolGroupAddr) 29 | { 30 | Pools = new List(); 31 | ConnectionString = connStr; 32 | PoolGroupAddress = poolGroupAddr; 33 | } 34 | 35 | public List Pools { get; private set; } 36 | public string ConnectionString { get; private set; } 37 | public ulong PoolGroupAddress { get; private set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SDbgExt/WinDbgExt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | 21 | PDEBUG_CLIENT g_Client; 22 | WINDBG_EXTENSION_APIS ExtensionApis; 23 | USHORT SavedMajorVersion; 24 | USHORT SavedMinorVersion; 25 | 26 | DBG_API DebugExtensionInitialize(PULONG Version, PULONG Flags) 27 | { 28 | UNREFERENCED_PARAMETER(Version); 29 | UNREFERENCED_PARAMETER(Flags); 30 | 31 | ExtensionApis.nSize = sizeof (ExtensionApis); 32 | HRESULT hr = S_OK; 33 | 34 | IDebugControl *ctrl = NULL; 35 | hr = DebugCreate(__uuidof(IDebugControl), (PVOID*)&ctrl); 36 | 37 | if ((hr = ctrl->GetWindbgExtensionApis64((PWINDBG_EXTENSION_APIS64)&ExtensionApis)) != S_OK) { 38 | return hr; 39 | } 40 | 41 | return S_OK; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /SDbgM/WinDbg/Name2EE.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.WinDbg 25 | { 26 | internal class Name2EE : IPluginMethod 27 | { 28 | public bool Run(SptWrapper wrapper, string args) 29 | { 30 | string[] argSplit = args.Split(' '); 31 | 32 | string moduleName = argSplit[0]; 33 | string typeName = argSplit[1]; 34 | 35 | if (argSplit.Length != 0) 36 | { 37 | wrapper.DbgOutput("Usage: !name2ee "); 38 | } 39 | 40 | return true; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SDbgCore/idl/CoreApi.idl: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | import "oaidl.idl"; 19 | import "ocidl.idl"; 20 | import "ClrData.idl"; 21 | 22 | import "idl\_IXCLRDataProcess3.idl"; 23 | import "idl\_IClrProcess.idl"; 24 | import "idl\_IClrObject.idl"; 25 | import "idl\_ISDbgExt.idl"; 26 | 27 | [ 28 | uuid(D90CA04C-0A5E-4E81-9F53-83EFB19B3EAD) 29 | ] 30 | library SDbgCore 31 | { 32 | interface IClrObjectArray; 33 | interface IClrObject; 34 | interface IDacMemoryAccess; 35 | interface IXCLRDataProcess3; 36 | interface IClrProcess; 37 | interface ISDbgExt; 38 | 39 | interface IEnumHashtableBatchCallback; 40 | interface IEnumObjectsBatchCallback; 41 | interface IEnumFieldsCallback; 42 | interface IDbgHelper; 43 | interface ISDbgBootstrapper; 44 | enum CorElementType; 45 | } -------------------------------------------------------------------------------- /SDbgCore/inc/SDbgCoreApi.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #import "..\..\lib\SDbgCore.tlb" no_namespace, raw_interfaces_only 20 | #import "..\..\lib\XCLRData.tlb" rename_namespace("XCLRData"), raw_interfaces_only, exclude("GUID", "_EXCEPTION_RECORD64", "IUnknown") 21 | 22 | typedef ULONG64 CLRDATA_ADDRESS; 23 | 24 | #ifdef SDBGAPIEXPORTS 25 | #define SDBGAPI __declspec(dllexport) 26 | #elif defined(SDBGEXT_EXPORTS) 27 | #define SDBGAPI __declspec(dllexport) 28 | #elif defined(SDBGCORE_USELIB) 29 | #define SDBGAPI 30 | #else 31 | #define SDBGAPI __declspec(dllimport) 32 | #endif 33 | 34 | #define RETURN_IF_FAILED(exp) if (FAILED(hr = (exp))) return hr; 35 | 36 | HRESULT SDBGAPI CreateClrProcess(IXCLRDataProcess3 *pDac, IDacMemoryAccess *dcma, IClrProcess **ret); -------------------------------------------------------------------------------- /SDbgM/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SDbgM")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SDbgM")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("54d70469-52ea-402f-93ba-7cedb62ab7fe")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SDbgExt2Tests/WorkstationHeapTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(WorkstationHeapTests) 10 | { 11 | public: 12 | ADD_BASIC_TEST_INIT 13 | 14 | TEST_METHOD(ClrGcHeapData_Basic) 15 | { 16 | ClrGcHeapData gcData = {}; 17 | auto hr = proc->GetGCHeapData(&gcData); 18 | 19 | ASSERT_SOK(hr); 20 | ASSERT_EQUAL((UINT)1, gcData.HeapCount); 21 | ASSERT_EQUAL(1, (BOOL)gcData.HeapsValid); 22 | ASSERT_EQUAL(0, (BOOL)gcData.ServerMode); 23 | } 24 | 25 | TEST_METHOD(ClrGcHeapList_Basic) 26 | { 27 | ClrGcHeapData gcData = {}; 28 | proc->GetGCHeapData(&gcData); 29 | 30 | ClrGcHeapStaticData gcsData = {}; 31 | auto hr = proc->GetGCHeapStaticData(&gcsData); 32 | 33 | ClrGcHeapSegmentData segData = {}; 34 | proc->GetHeapSegmentData(gcsData.Generations[0].start_segment, &segData); 35 | 36 | ASSERT_SOK(hr); 37 | } 38 | 39 | TEST_METHOD(ClrGcHeap_EnumerateObjects) 40 | { 41 | int n = 0; 42 | 43 | auto cb = [&n](ClrObjectData objData)->BOOL { 44 | n++; 45 | return TRUE; 46 | }; 47 | 48 | CComObject adapt; 49 | adapt.Init(cb); 50 | 51 | ext->EnumHeapObjects(&adapt); 52 | 53 | #ifndef _WIN64 54 | #define ExpectedHeapObjects 547 55 | #else 56 | #define ExpectedHeapObjects 355 57 | #endif 58 | Assert::AreEqual(ExpectedHeapObjects, n); 59 | } 60 | 61 | }; 62 | } -------------------------------------------------------------------------------- /SDbgExt/IP2MD.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include "..\SDbgCore\inc\ClrObject.h" 21 | #include 22 | #include 23 | #include "WinDbgTableFormatter.h" 24 | 25 | DBG_FUNC(ip2md) 26 | { 27 | DBG_PREAMBLE; 28 | UNREFERENCED_PARAMETER(hr); 29 | 30 | auto tokens = SPT::Util::Tokenize(args); 31 | if (tokens.size() != 1) 32 | { 33 | dwdprintf(dbg.Control, L"Usage: ip2md \r\n"); 34 | } 35 | 36 | CLRDATA_ADDRESS ip = GetExpression(tokens[0]); 37 | CLRDATA_ADDRESS mdAddr; 38 | 39 | if (FAILED(dbg.XCLR->GetMethodDescPtrFromIP(ip, &mdAddr))) 40 | { 41 | dwdprintf(dbg.Control, L"Failed to request MethodData, not in JIT code range"); 42 | } 43 | 44 | dwdprintf(dbg.Control, L"MethodDesc: %p\r\n", mdAddr); 45 | 46 | DumpMD_Impl(&dbg, mdAddr); 47 | 48 | return S_OK; 49 | } -------------------------------------------------------------------------------- /SDbgMTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SDbgMTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SDbgMTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7b3ae30c-786a-46d8-849b-84981ded4b5e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SDbgM/SptWrapper/SptWrapper_Metadata.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Diagnostics; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using SDbgCore; 25 | using SPT.Managed.ClrObjects; 26 | 27 | namespace SPT.Managed 28 | { 29 | public partial class SptWrapper 30 | { 31 | public string GetMethodDescName(ulong mdAddr) 32 | { 33 | uint nameLen = 0; 34 | this.Dac.GetMethodDescName(mdAddr, 0, null, out nameLen); 35 | 36 | if (nameLen == 0) 37 | return ""; 38 | 39 | StringBuilder name = new StringBuilder((int)nameLen); 40 | Dac.GetMethodDescName(mdAddr, nameLen, name, out nameLen); 41 | 42 | return name.ToString(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SDbgExt/SR.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include 20 | 21 | #define RESOURCE_ENTRY(name, value) static LPCWSTR name() { return value; } 22 | 23 | struct SR 24 | { 25 | public: 26 | RESOURCE_ENTRY(GetDelegateMethod_Format, L"MethodDesc @ 0x%016p -> %s\r\n"); 27 | RESOURCE_ENTRY(GetDelegateMethod_Error, L"Unable to resolve delegate") 28 | 29 | RESOURCE_ENTRY(DumpThreadPoolQueues_Entry, L" 0x%016p | 0x%016p | 0x%016p | %s\r\n"); 30 | RESOURCE_ENTRY(DumpThreadPoolQueues_NewQueue, L"WorkQueue @ 0x%016p in domain 0x%016p\r\n\r\n"); 31 | RESOURCE_ENTRY(DumpThreadPoolQueues_Header, L" WorkItem | DelegateAddr | State | Delegate Name\r\n"); 32 | 33 | RESOURCE_ENTRY(DumpAspNetRequests_Header, L"ThreadID HttpContext StartTimeUTC URL + QS\r\n"); 34 | RESOURCE_ENTRY(DumpAspNetRequests_Entry, L"%8x 0x%016p %-20s %s%s%s\r\n"); 35 | }; -------------------------------------------------------------------------------- /SDbgExt/SDbgExtApiExports.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include 20 | 21 | #ifdef SDBGEXT_EXPORTS 22 | #define SDBGEXT_API __declspec(dllexport) 23 | #else 24 | #define SDBGEXT_API __declspec(dllimport) 25 | #endif 26 | 27 | struct IXCLRDataProcess3; 28 | struct IDacMemoryAccess; 29 | struct ISDbgExt; 30 | struct IClrProcess; 31 | 32 | interface IDebugClient; 33 | interface IDebugDataSpaces; 34 | interface ISDbgBootstrapper; 35 | 36 | extern "C" { 37 | HRESULT SDBGEXT_API CreateSDbgExt(IClrProcess *p, ISDbgExt **ext); 38 | HRESULT SDBGEXT_API InitIXCLRData(IDebugClient *cli, LPCWSTR corDacPathOverride, IXCLRDataProcess3 **ppDac); 39 | HRESULT SDBGEXT_API CreateDbgEngMemoryAccess(IDebugDataSpaces *data, IDacMemoryAccess **ret); 40 | 41 | HRESULT SDBGEXT_API CreateBootstrapper(ISDbgBootstrapper **ret); 42 | HRESULT SDBGEXT_API CreateBootsrapperFromWinDBG(IDebugClient *cli, ISDbgBootstrapper **ret); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /SDbgExt2Tests/ExpressionTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | #ifndef _WIN64 10 | TEST_CLASS(ExpressionTests) 11 | { 12 | public: 13 | ADD_TEST_INIT(L"..\\dumps\\x86\\dct_1.dmp") 14 | 15 | TEST_METHOD(Expression_BasicMemberAccess) 16 | { 17 | CLRDATA_ADDRESS ret; 18 | auto hr = ext->EvaluateExpression((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c1c2c, "boom"), L"m_target", &ret); 19 | 20 | ASSERT_SOK(hr); 21 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c22dc, "boom"), ret); 22 | } 23 | 24 | TEST_METHOD(Expression_NestedMemberAccess) 25 | { 26 | CLRDATA_ADDRESS ret; 27 | auto hr = ext->EvaluateExpression((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c1c2c, "boom"), L"m_target.m_peFileFactory", &ret); 28 | 29 | ASSERT_SOK(hr); 30 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c1c0c, "boom"), ret); 31 | } 32 | 33 | TEST_METHOD(Expression_DctLookupByKey) 34 | { 35 | CLRDATA_ADDRESS ret; 36 | auto hr = ext->EvaluateExpression((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c5980, "boom"), L"['en-us']", &ret); 37 | 38 | ASSERT_SOK(hr); 39 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c59f4, "boom"), ret); 40 | } 41 | 42 | TEST_METHOD(Expression_DctLookupByHash) 43 | { 44 | CLRDATA_ADDRESS ret; 45 | auto hr = ext->EvaluateExpression((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c5980, "boom"), L"[488897277]", &ret); 46 | 47 | ASSERT_SOK(hr); 48 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c59f4, "boom"), ret); 49 | } 50 | }; 51 | #endif 52 | } -------------------------------------------------------------------------------- /SDbgM/ClrObjects/SqlPool.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.ClrObjects 25 | { 26 | public class SqlPool 27 | { 28 | public SqlPool(ulong pool, string sid, uint state, uint waitCount, uint totalObjects) 29 | { 30 | Connections = new List(); 31 | PoolAddress = pool; 32 | SID = sid; 33 | State = (int)state; 34 | WaitCount = (int)waitCount; 35 | TotalObjects = (int)totalObjects; 36 | } 37 | 38 | public List Connections { get; private set; } 39 | public ulong PoolAddress { get; private set; } 40 | public string SID { get; private set; } 41 | public int State { get; private set; } 42 | public int WaitCount { get; private set; } 43 | public int TotalObjects { get; private set; } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SDbgCore/idl/_ClrTypes.idl: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | typedef struct AppDomainAndValue 19 | { 20 | CLRDATA_ADDRESS Domain; 21 | CLRDATA_ADDRESS Value; 22 | BOOL IsInitialized; 23 | } AppDomainAndValue; 24 | 25 | 26 | typedef struct ClrThreadContext 27 | { 28 | CLRDATA_ADDRESS ExecutionContext; 29 | CLRDATA_ADDRESS IllogicalCallContext; 30 | CLRDATA_ADDRESS LogicalCallContext; 31 | CLRDATA_ADDRESS HostContext; 32 | } ClrThreadContext; 33 | 34 | typedef enum ClrDateTimeKind { KIND_UNSPECIFIED, KIND_UTC, KIND_LOCAL } ClrDateTimeKind; 35 | 36 | typedef struct ClrDateTime 37 | { 38 | ULONG64 Ticks; 39 | ClrDateTimeKind Kind; 40 | 41 | UINT Year; 42 | UINT Month; 43 | UINT Day; 44 | 45 | UINT Hour; 46 | UINT Minute; 47 | UINT Second; 48 | UINT Millisecond; 49 | } ClrDateTime; 50 | 51 | typedef struct ClrHttpContext 52 | { 53 | ClrDateTime RequestStartTime; 54 | [string] BSTR RequestUrl; 55 | [string] BSTR QueryString; 56 | } ClrHttpContext; 57 | 58 | typedef struct ClrDelegateInfo 59 | { 60 | CLRDATA_ADDRESS Target; 61 | CLRDATA_ADDRESS MethodDesc; 62 | } ClrDelegateInfo; -------------------------------------------------------------------------------- /SDbgCore/inc/EnumAdaptors.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "SDbgCoreApi.h" 20 | #include 21 | 22 | template 23 | class CallbackAdaptorBase : 24 | public CComObjectRoot, 25 | public TInterface 26 | { 27 | BEGIN_COM_MAP(CallbackAdaptorBase) 28 | COM_INTERFACE_ENTRY(TInterface) 29 | END_COM_MAP() 30 | public: 31 | HRESULT Init(std::function cb) 32 | { 33 | m_cb = cb; 34 | return S_OK; 35 | } 36 | 37 | STDMETHODIMP Callback(TFunc o) 38 | { 39 | return m_cb(o) == TRUE ? S_OK : E_ABORT; 40 | } 41 | 42 | ULONG InternalAddRef() { return 1; } 43 | ULONG InternalRelease() { return 1; } 44 | private: 45 | void* operator new(size_t s); 46 | std::function m_cb; 47 | 48 | }; 49 | 50 | typedef CallbackAdaptorBase EnumThreadCallbackAdaptor; 51 | typedef CallbackAdaptorBase EnumHeapSegmentsCallbackAdaptor; 52 | typedef CallbackAdaptorBase EnumFieldsCallbackAdaptor; -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_GetHttpContextFromThread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | 20 | STDMETHODIMP CSDbgExt::GetHttpContextFromThread(ClrThreadContext ctx, ClrHttpContext *httpContext) 21 | { 22 | if (!ctx.HostContext) 23 | return E_INVALIDARG; 24 | 25 | ULONG64 requestStartTime; 26 | if (SUCCEEDED(m_proc->GetFieldValueBuffer(ctx.HostContext, L"_utcTimestamp", sizeof(ULONG64), &(requestStartTime), NULL))) 27 | { 28 | m_proc->GetDateTimeFromTicks(requestStartTime, &(httpContext->RequestStartTime)); 29 | } 30 | 31 | auto tryGetPath = [this, &ctx](LPWSTR expr)->BSTR { 32 | CComPtr dac; 33 | this->m_proc->GetCorDataAccess(&dac); 34 | 35 | CLRDATA_ADDRESS tmp; 36 | if (SUCCEEDED(this->EvaluateExpression(ctx.HostContext, expr, &tmp)) && tmp) 37 | { 38 | WCHAR buffer[1024] = { 0 }; 39 | if (SUCCEEDED(dac->GetObjectStringData(tmp, ARRAYSIZE(buffer), buffer, NULL))) 40 | { 41 | return SysAllocString(buffer); 42 | } 43 | } 44 | 45 | return NULL; 46 | }; 47 | 48 | httpContext->RequestUrl = tryGetPath(L"_request._path._virtualPath"); 49 | httpContext->QueryString = tryGetPath(L"_request._queryStringText"); 50 | 51 | return S_OK; 52 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/ServerThreadTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(ServerThreadTests) 10 | { 11 | public: 12 | #ifndef _WIN64 13 | #define SystemWebModule 0x000000005cf91000 14 | #define ExpectedHttpRuntimeStatics { { 0x013a35d8, 0x0b946300 }, { 0x013f3570, 0x01a30c0c } } 15 | 16 | ADD_TEST_INIT(L"..\\dumps\\x86\\iis_small.dmp") 17 | #else 18 | #define SystemWebModule 0x000007fcfd0d1000 19 | #define MyDllModule 0x000007fca7454f20 20 | #define HostAppDomain 0x00000096aa885230 21 | 22 | #define ExpectedHttpRuntimeStatics { { 0x000000925ee2dcc0, 0x00000093dfc38cb0 }, { 0x00000096aa885230, 0x000000925fd98aa8 } } 23 | 24 | ADD_TEST_INIT(L"..\\..\\dumps\\x64\\iis_small_2.dmp") 25 | #endif 26 | TEST_METHOD(FindStaticField_HttpRuntime) 27 | { 28 | AppDomainAndValue expectedValues[2] = ExpectedHttpRuntimeStatics; 29 | AppDomainAndValue values[3] = { }; 30 | ULONG32 numValues; 31 | 32 | CLRDATA_ADDRESS methodTable, field; 33 | p->FindTypeByName(L"System.Web.dll", L"System.Web.HttpRuntime", &methodTable); 34 | p->FindFieldByNameEx(methodTable, L"_theRuntime", &field, NULL); 35 | p->GetStaticFieldValues(field, 3, values, &numValues); 36 | Assert::AreEqual((ULONG32)2, numValues); 37 | 38 | for (ULONG32 a = 0; a < numValues; a++) 39 | { 40 | Assert::AreEqual(expectedValues[a].domain, values[a].domain); 41 | Assert::AreEqual(expectedValues[a].Value, values[a].Value); 42 | } 43 | } 44 | 45 | TEST_METHOD(GetModuleData_Server) 46 | { 47 | const CLRDATA_ADDRESS modAddr = SystemWebModule; 48 | 49 | ClrModuleData modData = {}; 50 | auto hr = proc->GetModuleData(modAddr, &modData); 51 | 52 | ASSERT_SOK(hr); 53 | Assert::AreEqual((SIZE_T)3, (SIZE_T)modData.DomainNeutralIndex); 54 | } 55 | }; 56 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/ServerHeapTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | #include 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | namespace SDbgExt2Tests2 9 | { 10 | TEST_CLASS(ServerHeapTests) 11 | { 12 | public: 13 | #ifndef _WIN64 14 | ADD_TEST_INIT(L"..\\dumps\\x86\\iis_small.dmp") 15 | #else 16 | ADD_TEST_INIT(L"..\\..\\dumps\\x64\\iis_small_2.dmp") 17 | #endif 18 | 19 | TEST_METHOD(ClrGcHeapList_Server) 20 | { 21 | ClrGcHeapData gcData = {}; 22 | proc->GetGCHeapData(&gcData); 23 | 24 | Assert::IsTrue(gcData.ServerMode == 1); 25 | Assert::AreEqual((UINT)8, gcData.HeapCount); 26 | 27 | std::vector heaps(gcData.HeapCount); 28 | auto hr = proc->GetGCHeapList(gcData.HeapCount, heaps.data(), 0); 29 | 30 | ASSERT_SOK(hr); 31 | } 32 | 33 | TEST_METHOD(ClrGcHeapData_Server) 34 | { 35 | ClrGcHeapData gcData = {}; 36 | proc->GetGCHeapData(&gcData); 37 | 38 | std::vector heaps(gcData.HeapCount); 39 | auto hr = proc->GetGCHeapList(gcData.HeapCount, heaps.data(), 0); 40 | 41 | ClrGcHeapStaticData gchData = {}; 42 | hr = proc->GetGCHeapDetails(heaps[0], &gchData); 43 | 44 | ASSERT_SOK(hr); 45 | } 46 | 47 | TEST_METHOD(ClrGcHeap_EnumerateObjects_Server) 48 | { 49 | int n = 0; 50 | 51 | auto cb = [&n](ClrObjectData objData)->BOOL { 52 | n++; 53 | return TRUE; 54 | }; 55 | 56 | CComObject adapt; 57 | adapt.Init(cb); 58 | 59 | ext->EnumHeapObjects(&adapt); 60 | 61 | Assert::AreEqual(BITNESS_CONDITIONAL(50475, 52100), n); 62 | } 63 | 64 | TEST_METHOD(GetDelegateInfo_MethodPtr) 65 | { 66 | ClrDelegateInfo di; 67 | auto hr = p->GetDelegateInfo((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x01a3630c, 0x000000925feb8e40), &di); 68 | 69 | ASSERT_SOK(hr); 70 | } 71 | 72 | }; 73 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/StaticFieldTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(StaticFieldTests) 10 | { 11 | public: 12 | #ifndef _WIN64 13 | ADD_TEST_INIT(L"..\\dumps\\x86\\statics.dmp") 14 | #else 15 | ADD_TEST_INIT(L"..\\..\\dumps\\x64\\statics.dmp") 16 | #endif 17 | TEST_METHOD(StaticField_Object) 18 | { 19 | StaticFieldTestImpl(L"_objectField", 0x02a023d8, 0x0000000002772e90); 20 | } 21 | 22 | TEST_METHOD(StaticField_Array) 23 | { 24 | StaticFieldTestImpl(L"_arrayField", 0x02a023e4, 0x0000000002772ea8); 25 | } 26 | 27 | TEST_METHOD(StaticField_String) 28 | { 29 | StaticFieldTestImpl(L"_stringField", 0x02a023b0, 0x0000000002772e58); 30 | } 31 | 32 | TEST_METHOD(StaticField_Generic) 33 | { 34 | StaticFieldTestImpl(L"_genericField", 0x02a02444, 0x0000000002772f68); 35 | } 36 | 37 | TEST_METHOD(StaticField_Struct) 38 | { 39 | StaticFieldTestImpl(L"_structField", 0x03a0334c, 0x0000000012775690); 40 | } 41 | 42 | 43 | private: 44 | void StaticFieldTestImpl(const BSTR field, CLRDATA_ADDRESS _32bitValue, CLRDATA_ADDRESS _64bitValue) 45 | { 46 | AppDomainAndValue expectedStatics = 47 | { BITNESS_CONDITIONAL(0x00ae72c0, 0x00000000006617a0), BITNESS_CONDITIONAL(_32bitValue, _64bitValue) }; 48 | 49 | AppDomainAndValue values; 50 | ULONG32 iValues; 51 | CLRDATA_ADDRESS fieldAddr, methodTable; 52 | p->FindTypeByName(L"SOSRevHelper.exe", L"SOSRevHelper.TestStaticsClass", &methodTable); 53 | p->FindFieldByNameEx(methodTable, field, &fieldAddr, NULL); 54 | auto hr = p->GetStaticFieldValues(fieldAddr, 1, &values, &iValues); 55 | 56 | ASSERT_SOK(hr); 57 | Assert::AreEqual((ULONG32)1, iValues); 58 | Assert::AreEqual(expectedStatics.domain, values.domain); 59 | Assert::AreEqual(expectedStatics.Value, values.Value); 60 | } 61 | 62 | }; 63 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/TestCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 4 | #include "..\SDbgExt\SDbgExtApi.h" 5 | #include "..\SDbgExt\SDbgExt.h" 6 | #include "..\SDbgExt\EnumAdaptors.h" 7 | 8 | class CSDbgTestModule : public ATL::CAtlDllModuleT { }; 9 | extern class CSDbgTestModule _AtlModule; 10 | 11 | void SetupTests(WCHAR *dumpFile, IClrProcess **p, ISDbgExt **ext, IXCLRDataProcess3 **proc); 12 | 13 | #ifndef _WIN64 14 | #define ADD_BASIC_TEST_INIT ADD_TEST_INIT(L"Q:\\spt\\Dumps\\x86\\basic.dmp") 15 | #else 16 | #define ADD_BASIC_TEST_INIT ADD_TEST_INIT(L"..\\..\\Dumps\\x64\\basic.dmp") 17 | #endif 18 | 19 | #define ADD_TEST_INIT(file) TEST_METHOD_INITIALIZE(Init) { SetupTests(file, &p, &ext, &proc); } \ 20 | TEST_METHOD_CLEANUP(Cleanup) { p->Release(); ext->Release(); proc->Release(); } \ 21 | private: \ 22 | IClrProcess *p; \ 23 | ISDbgExt *ext; \ 24 | IXCLRDataProcess3 *proc; \ 25 | public: \ 26 | 27 | 28 | #define ASSERT_SOK(hr) Assert::AreEqual(S_OK, hr); 29 | #define ASSERT_NOT_ZERO(x) Assert::IsTrue(x != 0); 30 | #define ASSERT_EQUAL(x,y) Assert::AreEqual(x, y); 31 | 32 | #ifndef _WIN64 33 | #define BITNESS_CONDITIONAL(_32bit, _64bit) _32bit 34 | #else 35 | #define BITNESS_CONDITIONAL(_32bit, _64bit) _64bit 36 | #endif 37 | 38 | namespace Microsoft 39 | { 40 | namespace VisualStudio 41 | { 42 | namespace CppUnitTestFramework 43 | { 44 | template<> static std::wstring ToString(const AppDomainAndValue& t) 45 | { 46 | WCHAR buffer[18*2+8] = {0}; 47 | swprintf_s(buffer, L"(0x%016I64x, 0x%016I64x)", t.domain, t.Value); 48 | 49 | return std::wstring(buffer); 50 | } 51 | 52 | template<> static std::wstring ToString(const DctEntry& t) 53 | { 54 | WCHAR buffer[24*2+16] = {0}; 55 | swprintf_s(buffer, L"(0x%016I64x, 0x%016I64x, 0x%016I64x)", t.EntryPtr, t.KeyPtr, t.ValuePtr); 56 | 57 | return std::wstring(buffer); 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /SDbgM/SafeNativeMethods.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Runtime.InteropServices; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using SDbgCore; 25 | 26 | namespace SPT.Managed 27 | { 28 | internal static class SafeNativeMethods 29 | { 30 | public static ISDbgBootstrapper GetBoostrapper() 31 | { 32 | ISDbgBootstrapper bootstrapper = null; 33 | if (Environment.Is64BitProcess) 34 | { 35 | CreateBootstrapper_x64(out bootstrapper); 36 | } 37 | else 38 | { 39 | CreateBootstrapper_x86(out bootstrapper); 40 | } 41 | return bootstrapper; 42 | } 43 | 44 | [DllImport("spt.dll", EntryPoint = "CreateBootstrapper", CallingConvention = CallingConvention.Cdecl)] 45 | private static extern void CreateBootstrapper_x86([MarshalAs(UnmanagedType.Interface)] out ISDbgBootstrapper bootstrapper); 46 | 47 | [DllImport("spt_64.dll", EntryPoint = "CreateBootstrapper", CallingConvention = CallingConvention.Cdecl)] 48 | private static extern void CreateBootstrapper_x64([MarshalAs(UnmanagedType.Interface)] out ISDbgBootstrapper bootstrapper); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /SDbgM/WinDbg/Stubs.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.WinDbg 25 | { 26 | internal static class Stubs 27 | { 28 | private static bool RunMethod(SptWrapper wrapper, string args) 29 | where T : IPluginMethod, new() 30 | { 31 | var plugin = new T(); 32 | using (wrapper) 33 | { 34 | try 35 | { 36 | return plugin.Run(wrapper, args); 37 | } 38 | catch (Exception ex) 39 | { 40 | wrapper.DbgOutput(ex.ToString()); 41 | return false; 42 | } 43 | } 44 | } 45 | 46 | public static bool name2ee(SptWrapper wrapper, string args) 47 | { 48 | return RunMethod(wrapper, args); 49 | } 50 | 51 | public static bool dumpmd(SptWrapper wrapper, string args) 52 | { 53 | return RunMethod(wrapper, args); 54 | } 55 | 56 | public static bool threads(SptWrapper wrapper, string args) 57 | { 58 | return RunMethod(wrapper, args); 59 | } 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SDbgMTests/ObjectProxyTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using SPT.Managed; 4 | 5 | namespace SDbgMTests 6 | { 7 | [TestClass] 8 | public class ObjectProxyTests 9 | { 10 | private SptWrapper _ext; 11 | 12 | [TestInitialize] 13 | public void Init() 14 | { 15 | _ext = Util.CreateFromDump(@"Q:\spt\Dumps\x86\sql.dmp"); 16 | } 17 | 18 | [TestMethod] 19 | public void ObjectProxy_String() 20 | { 21 | dynamic obj = _ext.GetObject(0x026642c0); 22 | dynamic txt = obj._commandText; 23 | 24 | Assert.IsInstanceOfType(txt, typeof(string)); 25 | Assert.AreEqual("select 9", txt); 26 | } 27 | 28 | [TestMethod] 29 | public void ObjectProxy_Int() 30 | { 31 | dynamic obj = _ext.GetObject(0x026642c0); 32 | dynamic timeout = obj._commandTimeout; 33 | 34 | Assert.IsInstanceOfType(timeout, typeof(int)); 35 | Assert.AreEqual(30, timeout); 36 | } 37 | 38 | [TestMethod] 39 | public void ObjectProxy_Object() 40 | { 41 | dynamic obj = _ext.GetObject(0x026642c0); 42 | dynamic obj2 = obj._activeConnection; 43 | 44 | Assert.IsInstanceOfType(obj2, typeof(ObjectProxy)); 45 | } 46 | 47 | [TestMethod] 48 | public void ObjectProxy_Array() 49 | { 50 | dynamic obj = _ext.GetObject(0x02511424); 51 | dynamic obj2 = obj._Entries; 52 | dynamic obj3 = obj2[1]; 53 | 54 | Assert.IsInstanceOfType(obj3, typeof(string)); 55 | Assert.AreEqual(@"Q:\Dev\SOSRevHelper\SOSRevHelper\bin\Debug\SOSRevHelper.exe.config", obj3); 56 | } 57 | 58 | [TestMethod] 59 | public void ObjectProxy_ConvertToAddress() 60 | { 61 | dynamic obj = _ext.GetObject(0x02511424); 62 | ulong addr = (ulong)obj; 63 | 64 | Assert.AreEqual((ulong)0x02511424, addr); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_EnumSqlConnectionPools.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include 21 | #include 22 | #include "SqlConnectionEnumerator.h" 23 | 24 | STDMETHODIMP CSDbgExt::EnumSqlConnectionPools(IEnumSqlConnectionPoolsCallback *cb, CLRDATA_ADDRESS targetFactory) 25 | { 26 | std::vector factories; 27 | if (!targetFactory) 28 | { 29 | IXCLRDataProcess3Ptr dac; 30 | m_proc->GetCorDataAccess(&dac); 31 | ClrAppDomainStoreData ad = {}; 32 | dac->GetAppDomainStoreData(&ad); 33 | std::vector fieldValues(ad.DomainCount); 34 | 35 | CLRDATA_ADDRESS typeMt, field; UINT numValues; 36 | if ( FAILED(m_proc->FindTypeByName(L"System.Data.dll", L"System.Data.SqlClient.SqlConnectionFactory", &typeMt)) 37 | || FAILED(m_proc->FindFieldByNameEx(typeMt, L"SingletonInstance", &field, NULL)) 38 | || FAILED(m_proc->GetStaticFieldValues(field, ad.DomainCount, fieldValues.data(), &numValues)) 39 | ) 40 | { 41 | return E_NOT_VALID_STATE; 42 | } 43 | 44 | factories.resize(fieldValues.size()); 45 | std::transform(fieldValues.begin(), fieldValues.end(), factories.begin(), [&factories](AppDomainAndValue val) { 46 | return val.Value; 47 | }); 48 | } 49 | else 50 | { 51 | factories.push_back(targetFactory); 52 | } 53 | 54 | if (factories.size() > 0) 55 | { 56 | return SqlConnectionEnumerator(cb, this).Enumerate(factories); 57 | } 58 | 59 | return E_INVALIDARG; 60 | } -------------------------------------------------------------------------------- /SDbgExt/CSDbgBootstrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 20 | #include 21 | #include 22 | 23 | class CSDbgBootstrapper : 24 | public ISDbgBootstrapper, 25 | public CComObjectRoot 26 | { 27 | BEGIN_COM_MAP(CSDbgBootstrapper) 28 | COM_INTERFACE_ENTRY(ISDbgBootstrapper) 29 | END_COM_MAP() 30 | 31 | public: 32 | CSDbgBootstrapper() 33 | : m_cli(nullptr), m_symOptions(0), m_isDumpFile(FALSE) 34 | { 35 | } 36 | 37 | STDMETHODIMP ConfigureSymbolPath(LPWSTR symbolPath) 38 | { 39 | m_symPath = symbolPath; 40 | return S_OK; 41 | } 42 | 43 | STDMETHODIMP ConfigureImagePath(LPWSTR imgPath) 44 | { 45 | m_imgPath = imgPath; 46 | return S_OK; 47 | } 48 | 49 | STDMETHODIMP ConfigureSymbolOptions(ULONG options) 50 | { 51 | m_symOptions = options; 52 | return S_OK; 53 | } 54 | 55 | STDMETHODIMP InitFromLiveProcess(DWORD dwProcessId, ISDbgExt **ret); 56 | STDMETHODIMP InitFromDump(LPWSTR dumpFile, ISDbgExt **ext); 57 | 58 | STDMETHODIMP Init(ISDbgExt **ret); 59 | 60 | void setClient(IDebugClient *cli) 61 | { 62 | m_cli = cli; 63 | } 64 | 65 | void setIsDump(BOOL isDump) 66 | { 67 | m_isDumpFile = isDump; 68 | } 69 | 70 | private: 71 | 72 | HRESULT EnsureDbgClient(); 73 | HRESULT InitIXCLRDataFromWinDBG(WINDBG_EXTENSION_APIS64 *apis, IXCLRDataProcess3 **ppDac); 74 | 75 | std::wstring m_symPath; 76 | std::wstring m_imgPath; 77 | ULONG m_symOptions; 78 | CComPtr m_cli; 79 | BOOL m_isDumpFile; 80 | }; -------------------------------------------------------------------------------- /SDbgM/ClrObjects/SqlConnection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using SDbgCore; 24 | 25 | namespace SPT.Managed.ClrObjects 26 | { 27 | public class SqlConnection 28 | { 29 | public SqlConnection(ulong conn, uint state, ClrDateTime createTime, uint pooledCount, int isOpen, uint asyncCommandCount, ulong cmdAddr, string cmdText, uint timeout) 30 | { 31 | ConnectionAddress = conn; 32 | State = (int)state; 33 | 34 | CreateTime = DateTime.SpecifyKind(new DateTime((long)createTime.Ticks), (DateTimeKind)createTime.Kind); 35 | PooledCount = (int)pooledCount; 36 | IsOpen = (isOpen != 0); 37 | AsyncCommandCount = (int)asyncCommandCount; 38 | 39 | CommandAddress = cmdAddr; 40 | CommandText = cmdText; 41 | CommandTimeout = (int)timeout; 42 | } 43 | 44 | public ulong ConnectionAddress { get; private set; } 45 | public int State { get; private set; } 46 | public DateTime CreateTime { get; private set; } 47 | public int PooledCount { get; private set; } 48 | public bool IsOpen { get; private set; } 49 | public int AsyncCommandCount { get; private set; } 50 | 51 | public ulong CommandAddress { get; private set; } 52 | public string CommandText { get; private set; } 53 | public int CommandTimeout { get; private set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /SDbgExt2Tests/AppDomainTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | #include 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | namespace SDbgExt2Tests2 9 | { 10 | TEST_CLASS(AppDomainTests) 11 | { 12 | public: 13 | ADD_BASIC_TEST_INIT 14 | 15 | TEST_METHOD(ClrAppDomainStoreData_Basic) 16 | { 17 | ClrAppDomainStoreData ads = {}; 18 | auto hr = proc->GetAppDomainStoreData(&ads); 19 | 20 | Assert::AreEqual(S_OK, hr); 21 | Assert::AreEqual((LONG)1, ads.DomainCount); 22 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x749174d8, 0x000007fd073166e0), ads.SystemDomain); 23 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x74917180, 0x000007fd07316100), ads.SharedDomain); 24 | } 25 | 26 | TEST_METHOD(ClrAppDomainList_Basic) 27 | { 28 | ClrAppDomainStoreData ads = {}; 29 | auto hr = proc->GetAppDomainStoreData(&ads); 30 | 31 | ULONG32 numDomains = ads.DomainCount + 2; 32 | auto domains = std::vector(numDomains); 33 | 34 | hr = proc->GetAppDomainList(ads.DomainCount, domains.data() + 2, 0); 35 | 36 | ASSERT_SOK(hr); 37 | ASSERT_NOT_ZERO(domains[2]); 38 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x014972d0, 0x0000000000c317a0), domains[2]); 39 | } 40 | 41 | TEST_METHOD(ClrAssemblyList_Basic) 42 | { 43 | CLRDATA_ADDRESS domain; 44 | auto hr = proc->GetAppDomainList(1, &domain, 0); 45 | 46 | ClrAppDomainData adData = {}; 47 | hr = proc->GetAppDomainData(domain, &adData); 48 | 49 | auto asms = std::vector(adData.AssemblyCount); 50 | hr = proc->GetAssemblyList(domain, adData.AssemblyCount, asms.data(), NULL); 51 | 52 | ASSERT_SOK(hr); 53 | ASSERT_NOT_ZERO(asms[0]); 54 | } 55 | 56 | TEST_METHOD(ClrAppDomainData_Basic) 57 | { 58 | CLRDATA_ADDRESS domain; 59 | auto hr = proc->GetAppDomainList(1, &domain, 0); 60 | 61 | ClrAppDomainData adData = {}; 62 | hr = proc->GetAppDomainData(domain, &adData); 63 | 64 | ASSERT_SOK(hr); 65 | ASSERT_NOT_ZERO(adData.AppDomainPtr); 66 | ASSERT_EQUAL((LONG)3, adData.AssemblyCount); 67 | ASSERT_EQUAL((LONG)0, adData.FailedAssemblyCount); 68 | ASSERT_EQUAL((int)STAGE_OPEN, (int)adData.AppDomainStage); 69 | } 70 | }; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /SDbgCore/idl/_IClrObject.idl: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | import "ClrData.idl"; 19 | 20 | interface IClrObject; 21 | 22 | [ 23 | local, 24 | object, 25 | uuid(E46D45EC-36EF-4DE3-9077-B03F386F4CDF) 26 | ] 27 | interface IClrObjectArray : IUnknown 28 | { 29 | LONG GetSize(); 30 | HRESULT GetItemAddr([in] ULONG32 idx, [out, retval] CLRDATA_ADDRESS *addr) = 0; 31 | HRESULT GetItemObj([in] ULONG32 idx, [out, retval] IClrObject **ret) = 0; 32 | }; 33 | 34 | [ 35 | local, 36 | object, 37 | uuid(AA53AC80-D86E-47CE-ABE9-69C3C82B58C7) 38 | ] 39 | interface IClrObject : IUnknown 40 | { 41 | BOOL IsValid(); 42 | CLRDATA_ADDRESS Address(); 43 | HRESULT GetFieldValueAddr([in] LPWSTR field, [out, retval] CLRDATA_ADDRESS *ret); 44 | HRESULT GetFieldValueObj([in] LPWSTR field, [out, retval] IClrObject **ret); 45 | HRESULT GetFieldValueUInt32([in] LPWSTR field, [out, retval] UINT32 *val); 46 | HRESULT GetFieldValueWSTR([in] LPWSTR field, [in] ULONG32 iNumChars, [in, out] LPWSTR buffer, [out] ULONG *bytesRead); 47 | HRESULT GetFieldValueArray([in] LPWSTR field, [out, retval] IClrObjectArray **ret); 48 | HRESULT GetTypeName([in] ULONG32 cchBuffer, [in, out] LPWSTR buffer, [out] ULONG *nameLen); 49 | HRESULT GetMethodTable([out] CLRDATA_ADDRESS *mt); 50 | }; 51 | 52 | [ 53 | object, 54 | local, 55 | uuid(D6AE6FAF-DEE6-4D52-ABA4-2C2320DBADBB) 56 | ] 57 | interface IDacMemoryAccess : IUnknown 58 | { 59 | [local] HRESULT ReadVirtual([in] ULONG64 Offset, [out] LPVOID Buffer, [in] ULONG BufferSize, [out] ULONG *BytesRead); 60 | HRESULT GetThreadStack([in] DWORD osThreadId, [out] CLRDATA_ADDRESS *stackBase, [out] CLRDATA_ADDRESS *stackLimit); 61 | }; -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_EnumHeapObjects.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include "..\SDbgCore\inc\EnumAdaptors.h" 21 | #include 22 | 23 | #define Align(addr) (addr + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1) 24 | 25 | HRESULT CSDbgExt::EnumHeapObjects(IEnumObjectsCallback *cb) 26 | { 27 | IEnumObjectsCallbackPtr cbPtr(cb); 28 | CComPtr dac; 29 | m_proc->GetCorDataAccess(&dac); 30 | 31 | struct EnumSegmentsState 32 | { 33 | CComPtr wrappedCb; 34 | IXCLRDataProcess3 *pDac; 35 | CLRDATA_ADDRESS FreeMT; 36 | }; 37 | 38 | auto cbWrapper = GetObjectEnumCallback(cbPtr); 39 | 40 | HRESULT hr = S_OK; 41 | 42 | ClrUsefulGlobalsData ug = {}; 43 | RETURN_IF_FAILED(dac->GetUsefulGlobals(&ug)); 44 | 45 | EnumSegmentsState outerState = { cbPtr, dac, ug.FreeMethodTable }; 46 | 47 | auto heapCb = [&outerState, &cbWrapper](ClrGcHeapSegmentData segment)->BOOL { 48 | CLRDATA_ADDRESS currObj = segment.AllocBegin; 49 | while(currObj < segment.Allocated) 50 | { 51 | ClrObjectData od = {}; 52 | HRESULT hr = outerState.pDac->GetObjectData(currObj, &od); 53 | od.ObjectAddress = currObj; 54 | 55 | if (FAILED(hr)) 56 | { 57 | currObj += sizeof(void*); 58 | } 59 | else 60 | { 61 | if (FAILED(cbWrapper(od, FALSE))) 62 | { 63 | return FALSE; 64 | } 65 | currObj = Align(currObj + od.Size); 66 | } 67 | } 68 | 69 | return TRUE; 70 | }; 71 | 72 | CComObject adapt; 73 | adapt.Init(heapCb); 74 | 75 | RETURN_IF_FAILED(m_proc->EnumHeapSegments(&adapt)); 76 | 77 | ClrObjectData junk = {}; 78 | cbWrapper(junk, TRUE); 79 | 80 | return S_OK; 81 | } 82 | -------------------------------------------------------------------------------- /SDbgExt/EnumAdaptors.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "..\SDbgCore\inc\EnumAdaptors.h" 20 | #include "SDBgExtApi.h" 21 | #include 22 | 23 | typedef CallbackAdaptorBase EnumObjectsCallbackAdaptor; 24 | typedef CallbackAdaptorBase EnumDctAdaptor; 25 | typedef CallbackAdaptorBase EnumThreadPoolAdaptor; 26 | 27 | template 28 | std::function GetEnumCallbackWrapper(TBaseInterface *cbPtr, size_t maxBufferSize) 29 | { 30 | std::function cbWrapper; 31 | 32 | CComPtr batchCb; 33 | BOOL isBatch = SUCCEEDED(cbPtr->QueryInterface(__uuidof(TBatchInterface), (PVOID*)&batchCb)); 34 | 35 | if (isBatch) 36 | { 37 | std::vector buffer; 38 | cbWrapper = [batchCb, buffer, maxBufferSize](TItem od, BOOL flush) mutable { 39 | if (!flush) 40 | { 41 | buffer.push_back(od); 42 | if (buffer.size() >= maxBufferSize) 43 | { 44 | auto hr = batchCb->Callback((DWORD)buffer.size(), buffer.data()); 45 | buffer.clear(); 46 | return hr; 47 | } 48 | return S_OK; 49 | } 50 | else if (buffer.size() > 0) 51 | { 52 | return batchCb->Callback((DWORD)buffer.size(), buffer.data()); 53 | } 54 | else 55 | { 56 | return S_OK; 57 | } 58 | }; 59 | } 60 | else 61 | { 62 | CComPtr cb(cbPtr); 63 | cbWrapper = [cb](TItem od, BOOL flush) { 64 | if (!flush) 65 | { 66 | return cb->Callback(od); 67 | } 68 | else 69 | { 70 | return S_FALSE; 71 | } 72 | }; 73 | } 74 | 75 | return cbWrapper; 76 | } 77 | -------------------------------------------------------------------------------- /SDbgExt/DictionaryEnumerator.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 20 | #include "SDbgExtApi.h" 21 | 22 | class DctEnumerator 23 | { 24 | public: 25 | DctEnumerator(IClrProcess *proc) 26 | : m_dac(proc) 27 | { 28 | } 29 | 30 | HRESULT EnumerateDctEntries(CLRDATA_ADDRESS dctObj, IEnumHashtableCallback *cb); 31 | HRESULT FindDctEntryByKey(CLRDATA_ADDRESS dctObj, LPCWSTR key, CLRDATA_ADDRESS *targetAddr); 32 | HRESULT FindDctEntryByHash(CLRDATA_ADDRESS dctObj, UINT32 hash, CLRDATA_ADDRESS *targetAddr); 33 | 34 | private: 35 | CComPtr m_dac; 36 | 37 | HRESULT EnumerateDctEntriesImpl(CLRDATA_ADDRESS dctObj, CLRDATA_ADDRESS methodTable 38 | , WCHAR *bucketsName, WCHAR *keyFieldName, WCHAR *valFieldName, WCHAR *hashFieldName, IEnumHashtableCallback *cb); 39 | 40 | HRESULT GetEntryOffsets(CLRDATA_ADDRESS entriesPtr, WCHAR *keyFieldName, WCHAR *valFieldName, WCHAR *hashFieldName, 41 | ULONG *keyOffset, ULONG *valueOffset, ULONG *hashCodeOffset, 42 | CLRDATA_ADDRESS *arrayBase, ULONG *arrayElementSize, ULONG *arrayEntries, BOOL *elementsAreClass); 43 | 44 | HRESULT ReadEntries(DWORD arrayEntries, CLRDATA_ADDRESS bucketArrayBase, CLRDATA_ADDRESS arrayDataBase, ULONG arrayElementSize, 45 | ULONG keyOffset, ULONG valOffset, ULONG hashCodeOffset, BOOL elementsAreClass, IEnumHashtableCallback *cb); 46 | 47 | HRESULT ReadEntry(ULONG keyOffset, ULONG valueOffset, ULONG hashCodeOffset, CLRDATA_ADDRESS bucketArrayBase, CLRDATA_ADDRESS arrayDataPtr, BOOL elementIsClass, std::function cb); 48 | 49 | HRESULT EnumerateHybridListEntries(CLRDATA_ADDRESS listObj, IEnumHashtableCallback *cb); 50 | HRESULT EnumerateConcurrentDictionaryEntries(CLRDATA_ADDRESS listObj, IEnumHashtableCallback *cb); 51 | }; -------------------------------------------------------------------------------- /SDbgExt/WinDbgExt.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "SDbgExtApi.h" 21 | #define KDEXT_64BIT 22 | #include 23 | #include 24 | #include "SR.h" 25 | #include "..\SDbgCore\inc\EnumAdaptors.h" 26 | #include "EnumAdaptors.h" 27 | #include 28 | #include 29 | 30 | #define DBG_API extern "C" __declspec(dllexport) HRESULT 31 | #define DBG_FUNC(name) DBG_API name(PDEBUG_CLIENT clientPtr, PCSTR args) 32 | #define dwdprintf(ctrl, x,...) ctrl->ControlledOutputWide(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, ##x, __VA_ARGS__) 33 | //#define dwdprintf_res(ctrl, resName, ...) dwdprintf(ctrl, SR::resName(), __VA_ARGS__); 34 | 35 | #define DBG_PREAMBLE HRESULT hr = S_OK; \ 36 | CComPtr client(clientPtr); \ 37 | WinDbgInterfaces dbg(client); \ 38 | 39 | extern PDEBUG_CLIENT g_Client; 40 | 41 | struct WinDbgInterfaces 42 | { 43 | WinDbgInterfaces(CComPtr client) 44 | { 45 | CComPtr bootstrapper; 46 | CreateBootsrapperFromWinDBG(client, &bootstrapper); 47 | bootstrapper->Init(&Ext); 48 | 49 | Client = client; 50 | client.QueryInterface(&Control); 51 | 52 | Ext->GetProcess(&Process); 53 | Process->GetCorDataAccess(&XCLR); 54 | } 55 | 56 | CComPtr XCLR; 57 | CComPtr Process; 58 | CComPtr Ext; 59 | 60 | CComPtr Client; 61 | CComPtr Control; 62 | }; 63 | 64 | namespace SPT 65 | { 66 | namespace Util 67 | { 68 | std::vector Tokenize(CStringA str); 69 | }; 70 | }; 71 | 72 | // Common debug methods 73 | HRESULT GetModuleName(IXCLRDataProcess3 *proc, CLRDATA_ADDRESS modAddr, WCHAR buffer[512]); 74 | void DumpMD_Impl(WinDbgInterfaces *dbg, CLRDATA_ADDRESS mdAddr); 75 | HRESULT ExecuteOpCode(WinDbgInterfaces *dbg, UINT opcode, PCSTR subOpCode, PCSTR args); -------------------------------------------------------------------------------- /SDbgExt2Tests/FieldTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace SDbgExt2Tests2 8 | { 9 | TEST_CLASS(FieldTests) 10 | { 11 | public: 12 | ADD_BASIC_TEST_INIT 13 | 14 | TEST_METHOD(GetFieldValueString) 15 | { 16 | WCHAR buffer[200]; 17 | ULONG numBytesRead = 0; 18 | auto hr = p->GetFieldValueString(BITNESS_CONDITIONAL(0x02ec2420, 0x0000000002ec2f00), L"machineName", 200, buffer, &numBytesRead); 19 | 20 | ASSERT_SOK(hr); 21 | Assert::AreEqual(L".", buffer); 22 | Assert::AreEqual((ULONG)4, numBytesRead); 23 | } 24 | 25 | TEST_METHOD(GetFieldValueString_NullBufferReturnsStringLength) 26 | { 27 | ULONG numBytesRead = 0; 28 | auto hr = p->GetFieldValueString(BITNESS_CONDITIONAL(0x02ec2420, 0x0000000002ec2f00), L"machineName", 0, NULL, &numBytesRead); 29 | 30 | Assert::AreEqual((ULONG)4, numBytesRead); 31 | } 32 | 33 | TEST_METHOD(ClrObjectStringData_Basic) 34 | { 35 | WCHAR buffer[200]; 36 | ULONG32 strLen; 37 | auto hr = proc->GetObjectStringData(BITNESS_CONDITIONAL(0x02ec2318, 0x0000000002ec2d50), ARRAYSIZE(buffer), buffer, &strLen); 38 | 39 | ASSERT_SOK(hr); 40 | Assert::AreEqual(buffer, L"hello"); 41 | Assert::AreEqual((ULONG32)(sizeof(WCHAR) * 6), strLen); 42 | } 43 | 44 | TEST_METHOD(ClrObjectStringData_BufferSizeIsInCharacters) 45 | { 46 | WCHAR buffer[200]; 47 | ULONG32 strLen; 48 | // If this was in bytes it wouldn't read the entire string 49 | auto hr = proc->GetObjectStringData(BITNESS_CONDITIONAL(0x02ec2318, 0x0000000002ec2d50), 6, buffer, &strLen); 50 | 51 | ASSERT_SOK(hr); 52 | Assert::AreEqual(buffer, L"hello"); 53 | Assert::AreEqual((ULONG32)(sizeof(WCHAR) * 6), strLen); 54 | } 55 | 56 | #ifndef _WIN64 57 | TEST_METHOD(GetDelegateInfo_IP) 58 | { 59 | ClrDelegateInfo di = {}; 60 | auto hr = p->GetDelegateInfo(BITNESS_CONDITIONAL(0x02ec7f30, "break"), &di); 61 | 62 | ASSERT_SOK(hr); 63 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x02ec7eec, "break"), di.Target); 64 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x73396aac, "break"), di.MethodDesc); 65 | } 66 | 67 | TEST_METHOD(GetDelegateInfo_CodeHeader) 68 | { 69 | ClrDelegateInfo di = {}; 70 | 71 | auto hr = p->GetDelegateInfo(BITNESS_CONDITIONAL(0x02ec2394, "break"), &di); 72 | 73 | ASSERT_SOK(hr); 74 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x02ec2394, "break"), di.Target); 75 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x01153858, "break"), di.MethodDesc); 76 | } 77 | #endif 78 | }; 79 | } -------------------------------------------------------------------------------- /SDbgExt/DumpThreadPoolQueues.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include 21 | 22 | struct EnumState 23 | { 24 | CLRDATA_ADDRESS LastQueue; 25 | WinDbgInterfaces *dbg; 26 | std::hash_map DelegateNameLookup; 27 | }; 28 | 29 | class EnumThreadPoolQueuesCallback 30 | { 31 | public: 32 | EnumThreadPoolQueuesCallback(EnumState *ptr_es) 33 | : es(ptr_es) 34 | { } 35 | 36 | BOOL operator()(ThreadPoolWorkItem workItem) 37 | { 38 | if (es->LastQueue != workItem.Queue.Value) 39 | { 40 | dwdprintf(es->dbg->Control, SR::DumpThreadPoolQueues_NewQueue(), workItem.Queue.Value, workItem.Queue.domain); 41 | dwdprintf(es->dbg->Control, SR::DumpThreadPoolQueues_Header()); 42 | } 43 | 44 | auto item = es->DelegateNameLookup.find(workItem.DelegateMethodDesc); 45 | std::wstring delegateName; 46 | if (item == es->DelegateNameLookup.end()) 47 | { 48 | WCHAR buffer[512]; 49 | UINT32 numChars; 50 | 51 | if (SUCCEEDED(es->dbg->XCLR->GetMethodDescName(workItem.DelegateMethodDesc, ARRAYSIZE(buffer), buffer, &numChars))) 52 | { 53 | delegateName = std::wstring(buffer, numChars); 54 | } 55 | else 56 | { 57 | delegateName = std::wstring(L""); 58 | } 59 | es->DelegateNameLookup[workItem.DelegateMethodDesc] = delegateName; 60 | } 61 | else 62 | { 63 | delegateName = item->second; 64 | } 65 | 66 | dwdprintf(es->dbg->Control, SR::DumpThreadPoolQueues_Entry(), workItem.WorkItemPtr, workItem.DelegatePtr, workItem.StatePtr, delegateName.c_str()); 67 | 68 | es->LastQueue = workItem.Queue.Value; 69 | 70 | return TRUE; 71 | } 72 | private: 73 | EnumState *es; 74 | void *operator new(size_t s) { 75 | UNREFERENCED_PARAMETER(s); 76 | } 77 | }; 78 | 79 | DBG_FUNC(dumpthreadpoolqueues) 80 | { 81 | DBG_PREAMBLE; 82 | UNREFERENCED_PARAMETER(args); 83 | 84 | EnumState s = { 0, &dbg }; 85 | 86 | CComObject adapt; 87 | adapt.Init(EnumThreadPoolQueuesCallback(&s)); 88 | 89 | hr = dbg.Ext->EnumThreadPoolQueues(&adapt); 90 | 91 | return hr; 92 | } -------------------------------------------------------------------------------- /SDbgExt/DumpMD.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include "..\SDbgCore\inc\ClrObject.h" 21 | #include 22 | #include 23 | #include "WinDbgTableFormatter.h" 24 | 25 | DBG_FUNC(dumpmd_native) 26 | { 27 | DBG_PREAMBLE; 28 | UNREFERENCED_PARAMETER(hr); 29 | 30 | auto tokens = SPT::Util::Tokenize(args); 31 | if (tokens.size() != 1) 32 | { 33 | dwdprintf(dbg.Control, L"Usage: dumpmd \r\n"); 34 | } 35 | 36 | DumpMD_Impl(&dbg, GetExpression(tokens[0])); 37 | 38 | return S_OK; 39 | } 40 | 41 | void DumpMD_Impl(WinDbgInterfaces *dbg, CLRDATA_ADDRESS mdAddr) 42 | { 43 | ClrMethodDescData md = {}; 44 | dbg->XCLR->GetMethodDescData(mdAddr, NULL, &md, NULL, NULL, NULL); 45 | 46 | if (md.mdToken == NULL) 47 | return; 48 | 49 | WCHAR mdName[512]; 50 | UINT len; 51 | dbg->XCLR->GetMethodDescName(mdAddr, ARRAYSIZE(mdName), mdName, &len); 52 | 53 | ClrMethodTableData mtd = {}; 54 | dbg->XCLR->GetMethodTableData(md.MethodTable, &mtd); 55 | 56 | ClrMethodDescTransparencyData mttd = {}; 57 | dbg->XCLR->GetMethodDescTransparencyData(mdAddr, &mttd); 58 | 59 | WCHAR *transparency; 60 | if (!mttd.IsCalculated) 61 | { 62 | transparency = L"Not calculated"; 63 | } 64 | else if (!mttd.IsOpaque) 65 | { 66 | transparency = L"Transparent"; 67 | } 68 | else if (!mttd.IsSafe) 69 | { 70 | transparency = L"Critical"; 71 | } 72 | else 73 | { 74 | transparency = L"Safe Critical"; 75 | } 76 | 77 | WinDbgTableFormatter tf(dbg->Control); 78 | 79 | tf.AddColumn(L"Name", 13, TRUE); 80 | tf.AddColumn(L"Value", -1); 81 | 82 | tf.Column(L"Method Name:")->Column(L"%s", mdName)->NewRow() 83 | ->Column(L"Class:")->Column(L"%p", mtd.EEClass)->NewRow() 84 | ->Column(L"MethodTable:")->Column(L"%p", md.MethodTable)->NewRow() 85 | ->Column(L"mdToken:")->Column(L"%08x", md.mdToken)->NewRow() 86 | ->Column(L"Module:")->Column(L"%p", md.Module)->NewRow() 87 | ->Column(L"IsJitted:")->Column(L"%s", md.IsJitted ? L"yes" : L"no")->NewRow() 88 | ->Column(L"CodeAddr:")->Column(L"%p", md.CodeAddr)->NewRow() 89 | ->Column(L"Transparency:")->Column(L"%s", transparency)->NewRow(); 90 | 91 | } -------------------------------------------------------------------------------- /SDbgM/WinDbg/Threads.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using SDbgCore; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace SPT.Managed.WinDbg 26 | { 27 | internal class Threads : IPluginMethod 28 | { 29 | public bool Run(SptWrapper wrapper, string args) 30 | { 31 | var threads = wrapper.GetThreads(); 32 | 33 | TableWriter tw = wrapper.CreateTableWriter(); 34 | tw 35 | .AddColumn(4) 36 | .AddColumn(4) 37 | .AddColumn(4) 38 | .AddPointerColumn() 39 | .AddColumn(8) 40 | .AddColumn(11, true) 41 | .AddPointerColumn() 42 | .AddPointerColumn() 43 | .AddPointerColumn() 44 | .AddColumn(5, true) 45 | .AddColumn(3) 46 | .AddColumn(-1, true); 47 | 48 | tw.TextColumn("").TextColumn("ID").TextColumn("OSID").TextColumn("ThreadOb").TextColumn("State") 49 | .TextColumn("GC Mode").TextColumn("GC Alloc").TextColumn("Context").TextColumn("Domain ").TextColumn("Lock").TextColumn("Apt") 50 | .TextColumn("Exception") 51 | .NewRow(); 52 | 53 | foreach (var t in threads) 54 | { 55 | tw 56 | .HexColumn(0) 57 | .HexColumn(t.CorThreadId) 58 | .HexColumn(t.osThreadId) 59 | .PointerColumn(t.ThreadAddress) 60 | .HexColumn(t.State) 61 | .TextColumn(t.PreemptiveGCDisabled == 0 ? "Preemptive" : "Cooperative") 62 | .PointerColumn(t.GCAllocContext) 63 | .PointerColumn(t.GCAllocContextLimit) 64 | .PointerColumn(t.domain) 65 | .Column("{0}", t.LockCount) 66 | .TextColumn("MTA") 67 | .TextColumn("???"); 68 | 69 | tw.NewRow(); 70 | } 71 | 72 | return true; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_EvaluateExpression.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include "DictionaryEnumerator.h" 21 | #include 22 | 23 | #define RESET_BUFFER RETURN_IF_FAILED(hr); \ 24 | bufferPos = 0; \ 25 | ZeroMemory((void*)buffer.data(), buffer.size() * sizeof(WCHAR)); 26 | 27 | HRESULT CSDbgExt::EvaluateExpression(CLRDATA_ADDRESS rootAddr, LPWSTR expression, CLRDATA_ADDRESS *result) 28 | { 29 | std::wstring str(expression); 30 | HRESULT hr = S_OK; 31 | 32 | size_t len = str.length(); 33 | std::wstring buffer(len+1, '\0'); 34 | 35 | int bufferPos = 0; 36 | CLRDATA_ADDRESS currAddr = rootAddr; 37 | for (size_t a = 0; a < len; a++) 38 | { 39 | if (str[a] == L'.') 40 | { 41 | if (bufferPos == 0) //Invalid expression 42 | { 43 | hr = E_INVALIDARG; 44 | goto cleanup; 45 | } 46 | hr = m_proc->GetFieldValuePtr(currAddr, const_cast(buffer.c_str()), &currAddr); 47 | RESET_BUFFER 48 | } 49 | else if (str[a] == L'[') 50 | { 51 | if (bufferPos > 0) 52 | { 53 | hr = m_proc->GetFieldValuePtr(currAddr, const_cast(buffer.c_str()), &currAddr); 54 | } 55 | RESET_BUFFER 56 | } 57 | else if (str[a] == ']') //Dct lookup 58 | { 59 | if ((buffer[0] == '\'' && buffer[bufferPos-1] == '\'') || (buffer[0] == '"' && buffer[bufferPos-1] == '"')) 60 | { 61 | // It's a string 62 | int bufferLen = bufferPos - 2; 63 | std::wstring buffer2(buffer.data() + 1, bufferLen); 64 | 65 | DctEnumerator dctEnum(m_proc); 66 | hr = dctEnum.FindDctEntryByKey(currAddr, buffer2.c_str(), &currAddr); 67 | } 68 | else 69 | { 70 | // It's a hash code (we hope) 71 | ULONG32 hashCode = wcstoul(buffer.data(), NULL, 10); 72 | DctEnumerator dctEnum(m_proc); 73 | hr = dctEnum.FindDctEntryByHash(currAddr, hashCode, &currAddr); 74 | } 75 | RESET_BUFFER 76 | if ((a+1 < len) && (str[a+1] == L'.')) 77 | a++; 78 | } 79 | else 80 | { 81 | buffer[bufferPos++] = str[a]; 82 | } 83 | } 84 | if (bufferPos > 0) 85 | { 86 | hr = m_proc->GetFieldValuePtr(currAddr, const_cast(buffer.c_str()), &currAddr); 87 | } 88 | if (SUCCEEDED(hr)) 89 | *result = currAddr; 90 | cleanup: 91 | return hr; 92 | } 93 | 94 | #undef RESET_BUFFER -------------------------------------------------------------------------------- /SDbgCore/inc/ClrObjectArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "stdafx.h" 20 | 21 | class ClrObjectArray; 22 | typedef CComObject CClrObjectArray; 23 | 24 | class ClrObjectArray : 25 | public CComObjectRoot, 26 | public IClrObjectArray 27 | { 28 | public: 29 | 30 | static IClrObjectArray *Construct(IClrProcess *proc, CLRDATA_ADDRESS obj) 31 | { 32 | CClrObjectArray *arr; 33 | CClrObjectArray::CreateInstance(&arr); 34 | arr->AddRef(); 35 | arr->Init(proc, obj); 36 | 37 | return arr; 38 | } 39 | 40 | BEGIN_COM_MAP(ClrObjectArray) 41 | COM_INTERFACE_ENTRY(IClrObjectArray) 42 | END_COM_MAP() 43 | 44 | STDMETHODIMP GetItemAddr(ULONG32 idx, CLRDATA_ADDRESS *objAddr) 45 | { 46 | HRESULT hr = S_OK; 47 | if (FAILED(hr = EnsureInit())) 48 | return hr; 49 | 50 | if (idx >= m_arrayData.NumElements) 51 | return E_INVALIDARG; 52 | 53 | *objAddr = 0; 54 | CComPtr dac; 55 | m_proc->GetMemoryAccess(&dac); 56 | return dac->ReadVirtual(m_arrayData.FirstElement + (idx * m_arrayData.ElementSize), objAddr, sizeof(void*), NULL); 57 | } 58 | 59 | STDMETHODIMP GetItemObj(ULONG32 idx, IClrObject **ret) 60 | { 61 | CLRDATA_ADDRESS objAddr = 0; 62 | HRESULT hr = S_OK; 63 | RETURN_IF_FAILED(GetItemAddr(idx, &objAddr)); 64 | 65 | return m_proc->GetClrObject(objAddr, ret); 66 | } 67 | 68 | STDMETHODIMP_(LONG) GetSize() 69 | { 70 | if (FAILED(EnsureInit())) 71 | return -1; 72 | 73 | return m_arrayData.NumElements; 74 | } 75 | 76 | protected: 77 | ClrObjectArray() 78 | : m_arrayInit(FALSE) 79 | { } 80 | 81 | private: 82 | 83 | STDMETHODIMP EnsureInit() 84 | { 85 | HRESULT hr; 86 | if (!m_arrayInit) 87 | { 88 | ClrObjectData od = {}; 89 | CComPtr dac; 90 | m_proc->GetCorDataAccess(&dac); 91 | RETURN_IF_FAILED(dac->GetObjectData(m_addr, &od)); 92 | m_arrayData = od.ArrayData; 93 | m_arrayInit = TRUE; 94 | } 95 | return S_OK; 96 | } 97 | 98 | void Init(IClrProcess *proc, CLRDATA_ADDRESS obj) 99 | { 100 | m_addr = obj; 101 | m_proc = proc; 102 | } 103 | 104 | CComPtr m_proc; 105 | CLRDATA_ADDRESS m_addr; 106 | BOOL m_arrayInit; 107 | ClrArrayData m_arrayData; 108 | }; -------------------------------------------------------------------------------- /SDbgExt/DbgEngMemoryAccess.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "..\SDbgCore\inc\SDbgCoreApi.h" 20 | #include 21 | 22 | class DbgEngMemoryAccess : 23 | public CComObjectRoot, 24 | public IDacMemoryAccess 25 | { 26 | public: 27 | 28 | BEGIN_COM_MAP(DbgEngMemoryAccess) 29 | COM_INTERFACE_ENTRY(IDacMemoryAccess) 30 | END_COM_MAP() 31 | 32 | void Init(IDebugDataSpaces *data) 33 | { 34 | m_pData = data; 35 | } 36 | 37 | STDMETHODIMP ReadVirtual( 38 | ULONG64 Offset, 39 | PVOID Buffer, 40 | ULONG BufferSize, 41 | PULONG BytesRead 42 | ) 43 | { 44 | return m_pData->ReadVirtual(Offset, Buffer, BufferSize, BytesRead); 45 | } 46 | 47 | STDMETHODIMP GetThreadStack(DWORD osThreadId, CLRDATA_ADDRESS *stackBase, CLRDATA_ADDRESS *stackLimit) 48 | { 49 | struct CurrentThreadHolder 50 | { 51 | ULONG _origThread; 52 | CComPtr _dso; 53 | 54 | CurrentThreadHolder(ULONG origThread, CComPtr dso) 55 | { 56 | _origThread = origThread; 57 | _dso = dso; 58 | } 59 | ~CurrentThreadHolder() 60 | { 61 | _dso->SetCurrentThreadId(_origThread); 62 | } 63 | }; 64 | 65 | CComPtr dso; 66 | HRESULT hr; 67 | RETURN_IF_FAILED(m_pData->QueryInterface(__uuidof(IDebugSystemObjects), (PVOID*)&dso)); 68 | 69 | ULONG currThread = 0; 70 | dso->GetCurrentThreadId(&currThread); 71 | auto threadHolder = CurrentThreadHolder(currThread, dso); 72 | 73 | ULONG newThreadId = 0; 74 | RETURN_IF_FAILED(dso->GetThreadIdBySystemId(osThreadId, &newThreadId)); 75 | RETURN_IF_FAILED(dso->SetCurrentThreadId(newThreadId)); 76 | 77 | ULONG64 threadTebAddr = 0; 78 | dso->GetCurrentThreadTeb(&threadTebAddr); 79 | RETURN_IF_FAILED(CSDbgExt::GetThreadLimitsFromTEB(m_pData, threadTebAddr, stackBase, stackLimit)); 80 | 81 | /* 82 | 83 | CComPtr adv; 84 | dso.QueryInterface(&adv); 85 | 86 | CONTEXT ctx = {}; 87 | adv->GetThreadContext(&ctx, sizeof(CONTEXT)); 88 | 89 | #ifdef _M_X64 90 | *stackLimit = ctx.Rsp; 91 | #else 92 | *stackLimit = ctx.Esp; 93 | #endif 94 | */ 95 | 96 | return S_OK; 97 | } 98 | private: 99 | CComPtr m_pData; 100 | }; -------------------------------------------------------------------------------- /SDbgM/WinDbg/DumpMD.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using SDbgCore; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace SPT.Managed.WinDbg 26 | { 27 | internal class DumpMD : IPluginMethod 28 | { 29 | private string GetTransparency(SptWrapper wrapper, ulong mdAddr) 30 | { 31 | var mttd = wrapper.Dac.GetMethodDescTransparencyData(mdAddr); 32 | 33 | string transparency; 34 | if (mttd.IsCalculated == 0) 35 | { 36 | transparency = "Not calculated"; 37 | } 38 | else if (mttd.IsOpaque == 0) 39 | { 40 | transparency = "Transparent"; 41 | } 42 | else if (mttd.IsSafe != 0) 43 | { 44 | transparency = "Critical"; 45 | } 46 | else 47 | { 48 | transparency = "Safe Critical"; 49 | } 50 | 51 | return transparency; 52 | } 53 | 54 | public bool Run(SptWrapper wrapper, string args) 55 | { 56 | ulong addr = wrapper.GetExpression(args); 57 | 58 | ClrMethodDescData mdd; 59 | uint n = 0; 60 | wrapper.Dac.GetMethodDescData(addr, 0, out mdd, 0, null, out n); 61 | ClrMethodTableData mtd = wrapper.Dac.GetMethodTableData(mdd.MethodTable); 62 | 63 | string methodName = wrapper.GetMethodDescName(addr); 64 | 65 | var tr = wrapper.CreateTableWriter(); 66 | 67 | tr.AddColumn(17, true); 68 | tr.AddColumn(-1); 69 | 70 | tr.TextColumn("Method Name:").TextColumn(methodName.ToString()).NewRow() 71 | .TextColumn("Class:").PointerColumn(mtd.EEClass).NewRow() 72 | .TextColumn("MethodTable:").PointerColumn(mdd.MethodTable).NewRow() 73 | .TextColumn("mdToken:").Column("0x{0:x8}", mdd.mdToken).NewRow() 74 | .TextColumn("Module:").PointerColumn(mdd.Module).NewRow() 75 | .TextColumn("IsJitted:").TextColumn(mdd.IsJitted != 0 ? "yes" : "no").NewRow() 76 | .TextColumn("CodeAddr:").PointerColumn(mdd.CodeAddr).NewRow() 77 | .TextColumn("Transparency:").TextColumn(GetTransparency(wrapper, addr)).NewRow(); 78 | 79 | return true; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /SDbgCore/SDbgCore.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 | {a4f4b442-0789-48b5-8d84-33ba235703d4} 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | 64 | 65 | IDL 66 | 67 | 68 | IDL 69 | 70 | 71 | IDL 72 | 73 | 74 | IDL 75 | 76 | 77 | IDL 78 | 79 | 80 | IDL 81 | 82 | 83 | -------------------------------------------------------------------------------- /SDbgExt/SDbgExt.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "SDbgExtApi.h" 20 | #include "EnumAdaptors.h" 21 | #include 22 | #include 23 | 24 | class CSDbgExt : 25 | public CComObjectRoot, 26 | public ISDbgExt 27 | { 28 | public: 29 | static ISDbgExt *Construct(IClrProcess *p) 30 | { 31 | CComObject *obj; 32 | CComObject::CreateInstance(&obj); 33 | obj->AddRef(); 34 | obj->Init(p); 35 | 36 | return obj; 37 | } 38 | 39 | BEGIN_COM_MAP(CSDbgExt) 40 | COM_INTERFACE_ENTRY(ISDbgExt) 41 | END_COM_MAP() 42 | 43 | STDMETHODIMP GetProcess(IClrProcess **proc) 44 | { 45 | *proc = m_proc; 46 | (*proc)->AddRef(); 47 | return S_OK; 48 | } 49 | 50 | STDMETHODIMP GetObjectData(CLRDATA_ADDRESS objAddr, ClrObjectData *data) 51 | { 52 | CComPtr dac; 53 | m_proc->GetCorDataAccess(&dac); 54 | 55 | return dac->GetObjectData(objAddr, data); 56 | } 57 | 58 | STDMETHODIMP EnumStackObjects(DWORD corThreadId, IEnumObjectsCallback *cb); 59 | STDMETHODIMP EnumStackObjectsByThreadObj(CLRDATA_ADDRESS threadObj, IEnumObjectsCallback *cb); 60 | STDMETHODIMP EnumStackObjectsByStackParams(CLRDATA_ADDRESS stackBase, CLRDATA_ADDRESS stackLimit, IEnumObjectsCallback *cb); 61 | STDMETHODIMP EnumHeapObjects(IEnumObjectsCallback *cb); 62 | STDMETHODIMP EnumSqlConnectionPools(IEnumSqlConnectionPoolsCallback *cb, CLRDATA_ADDRESS targetFactory); 63 | STDMETHODIMP EnumHashtable(CLRDATA_ADDRESS dctObj, IEnumHashtableCallback *cb); 64 | STDMETHODIMP EnumThreadPoolQueues(IEnumThreadPoolCallback *tpQueueCb); 65 | STDMETHODIMP EvaluateExpression(CLRDATA_ADDRESS rootObj, LPWSTR expression, CLRDATA_ADDRESS *result); 66 | 67 | STDMETHODIMP FindDctEntryByHash(CLRDATA_ADDRESS dctObj, UINT32 hash, CLRDATA_ADDRESS *entryAddr); 68 | STDMETHODIMP GetHttpContextFromThread(ClrThreadContext ctx, ClrHttpContext *httpContext); 69 | 70 | static HRESULT GetThreadLimitsFromTEB(IDebugDataSpaces *data, CLRDATA_ADDRESS teb, CLRDATA_ADDRESS *stackBase, CLRDATA_ADDRESS *stackLimit); 71 | 72 | protected: 73 | CSDbgExt() 74 | { 75 | } 76 | 77 | private: 78 | void Init(IClrProcess *p) 79 | { 80 | m_proc = p; 81 | } 82 | 83 | std::function GetObjectEnumCallback(IEnumObjectsCallback *cb) 84 | { 85 | return GetEnumCallbackWrapper(cb, 100); 86 | } 87 | 88 | CComPtr m_proc; 89 | }; -------------------------------------------------------------------------------- /SDbgCore/src/ClrProcess_Heap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "..\inc\ClrProcess.h" 20 | #include 21 | #include 22 | #include "..\inc\ClrObject.h" 23 | 24 | HRESULT ClrProcess::EnumHeapSegments(IEnumHeapSegmentsCallback *cb) 25 | { 26 | ClrGcHeapData gcData = {}; 27 | HRESULT hr = S_OK; 28 | RETURN_IF_FAILED(m_pDac->GetGCHeapData(&gcData)); 29 | 30 | if (gcData.ServerMode) 31 | { 32 | return EnumHeapSegmentsServer(cb); 33 | } 34 | else 35 | { 36 | return EnumHeapSegmentsWorkstation(cb); 37 | } 38 | } 39 | 40 | HRESULT ClrProcess::EnumHeapSegmentsServer(IEnumHeapSegmentsCallback *cb) 41 | { 42 | ClrGcHeapData gcData = {}; 43 | m_pDac->GetGCHeapData(&gcData); 44 | 45 | std::vector heaps(gcData.HeapCount); 46 | auto hr = m_pDac->GetGCHeapList(gcData.HeapCount, heaps.data(), 0); 47 | 48 | for (auto heap : heaps) 49 | { 50 | ClrGcHeapStaticData gchData = {}; 51 | RETURN_IF_FAILED(m_pDac->GetGCHeapDetails(heap, &gchData)); 52 | 53 | hr = EnumHeapSegmentsImpl(gchData, cb); 54 | if (hr == S_FALSE) 55 | return S_FALSE; 56 | } 57 | 58 | return S_OK; 59 | } 60 | 61 | HRESULT ClrProcess::EnumHeapSegmentsWorkstation(IEnumHeapSegmentsCallback *cb) 62 | { 63 | ClrGcHeapStaticData gcsData = {}; 64 | HRESULT hr = S_OK; 65 | RETURN_IF_FAILED(m_pDac->GetGCHeapStaticData(&gcsData)); 66 | 67 | return EnumHeapSegmentsImpl(gcsData, cb); 68 | } 69 | 70 | HRESULT ClrProcess::EnumHeapSegmentsImpl(ClrGcHeapStaticData &gcsData, IEnumHeapSegmentsCallback *cb) 71 | { 72 | CLRDATA_ADDRESS currSegment = gcsData.Generations[2].start_segment; 73 | HRESULT hr = S_OK; 74 | BOOL visitedLOHSegment = FALSE; 75 | while (currSegment != NULL) 76 | { 77 | ClrGcHeapSegmentData segData = {}; 78 | RETURN_IF_FAILED(m_pDac->GetHeapSegmentData(currSegment, &segData)); 79 | 80 | if (segData.Segment == gcsData.Generations[0].start_segment) 81 | { 82 | segData.Allocated = gcsData.AllocAllocated; 83 | } 84 | // TODO: Does the current segment need to get set back on segData? 85 | // Segment looks like it's what we want and it seems like it's set. 86 | if (FAILED(cb->Callback(segData))) 87 | { 88 | return S_FALSE; 89 | } 90 | 91 | currSegment = segData.NextSegment; 92 | if (currSegment == NULL && !visitedLOHSegment) 93 | { 94 | currSegment = gcsData.Generations[3].start_segment; 95 | visitedLOHSegment = TRUE; 96 | } 97 | } 98 | return S_OK; 99 | } -------------------------------------------------------------------------------- /SDbgExt2Tests/SDbgExt2Tests2.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 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | Source Files 85 | 86 | 87 | -------------------------------------------------------------------------------- /SDbgExt2Tests/SqlTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | #include 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | namespace SDbgExt2Tests2 9 | { 10 | #ifndef _WIN64 11 | TEST_CLASS(SqlTests) 12 | { 13 | public: 14 | ADD_TEST_INIT(L"..\\dumps\\x86\\sql.dmp") 15 | 16 | struct PoolGroup 17 | { 18 | PoolGroup(std::wstring cs, CLRDATA_ADDRESS pg) 19 | : connString(cs), poolGroup(pg) 20 | {} 21 | 22 | std::wstring connString; 23 | CLRDATA_ADDRESS poolGroup; 24 | }; 25 | 26 | struct Pool 27 | { 28 | Pool(CLRDATA_ADDRESS conn, std::wstring sid, UINT state, UINT waitCount, UINT totalObjects) 29 | : pool(conn), sid(sid), state(state), waitCount(waitCount), totalObjects(totalObjects) 30 | {} 31 | 32 | CLRDATA_ADDRESS pool; 33 | std::wstring sid; 34 | UINT state; 35 | UINT waitCount; 36 | UINT totalObjects; 37 | }; 38 | 39 | struct Conn 40 | { 41 | Conn(CLRDATA_ADDRESS conn, UINT32 state, ClrDateTime createTime, UINT32 pooledCount, LONG isOpen, UINT32 asyncCommandCount, CLRDATA_ADDRESS cmd, LPWSTR cmdText, UINT32 timeout) 42 | : conn(conn), state(state), createTime(createTime), pooledCount(pooledCount), isOpen(isOpen), asyncCommandCount(asyncCommandCount), cmd(cmd), cmdText(cmdText), timeout(timeout) 43 | { 44 | } 45 | 46 | CLRDATA_ADDRESS conn; UINT32 state; ClrDateTime createTime; UINT32 pooledCount; LONG isOpen; UINT32 asyncCommandCount; CLRDATA_ADDRESS cmd; std::wstring cmdText; UINT32 timeout; 47 | }; 48 | 49 | 50 | struct TestCallbacks : 51 | public CComObjectRoot, 52 | public IEnumSqlConnectionPoolsCallback 53 | { 54 | BEGIN_COM_MAP(TestCallbacks) 55 | COM_INTERFACE_ENTRY(IEnumSqlConnectionPoolsCallback) 56 | END_COM_MAP() 57 | 58 | STDMETHODIMP OnFactory (CLRDATA_ADDRESS factory ) 59 | { 60 | seenFactories.push_back(factory); 61 | return S_OK; 62 | } 63 | STDMETHODIMP OnPoolGroup (LPWSTR connString, CLRDATA_ADDRESS poolGroup) 64 | { 65 | seenGroups.emplace_back(std::wstring(connString), poolGroup); 66 | return S_OK; 67 | } 68 | 69 | STDMETHODIMP OnPool(CLRDATA_ADDRESS pool, LPWSTR sid, UINT state, UINT waitCount, UINT totalObjects) 70 | { 71 | seenPools.emplace_back(pool, std::wstring(sid), state, waitCount, totalObjects); 72 | return S_OK; 73 | } 74 | 75 | STDMETHODIMP OnConnection(CLRDATA_ADDRESS conn, UINT32 state, ClrDateTime createTime, UINT32 pooledCount, LONG isOpen, UINT32 asyncCommandCount, CLRDATA_ADDRESS cmd, LPWSTR cmdText, UINT32 timeout) 76 | { 77 | Conn c(conn, state,createTime, pooledCount, isOpen, asyncCommandCount, cmd, cmdText, timeout); 78 | seenConnections.push_back(c); 79 | return S_OK; 80 | } 81 | 82 | std::vector seenConnections; 83 | std::vector seenPools; 84 | std::vector seenGroups; 85 | std::vector seenFactories; 86 | }; 87 | 88 | TEST_METHOD(DumpSqlConnectionPools) 89 | { 90 | CComObject *cb; 91 | CComObject::CreateInstance(&cb); 92 | cb->AddRef(); 93 | auto hr = ext->EnumSqlConnectionPools(cb, NULL); 94 | 95 | ASSERT_SOK(hr); 96 | Assert::AreEqual((size_t)7, cb->seenConnections.size()); 97 | 98 | cb->Release(); 99 | } 100 | 101 | }; 102 | #endif 103 | } -------------------------------------------------------------------------------- /SDbgM/ClrObjects/CorType.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.ClrObjects 25 | { 26 | internal static class CorType 27 | { 28 | public const uint ELEMENT_TYPE_END = 0x00; 29 | public const uint ELEMENT_TYPE_VOID = 0x01; 30 | public const uint ELEMENT_TYPE_BOOLEAN = 0x02; 31 | public const uint ELEMENT_TYPE_CHAR = 0x03; 32 | public const uint ELEMENT_TYPE_I1 = 0x04; 33 | public const uint ELEMENT_TYPE_U1 = 0x05; 34 | public const uint ELEMENT_TYPE_I2 = 0x06; 35 | public const uint ELEMENT_TYPE_U2 = 0x07; 36 | public const uint ELEMENT_TYPE_I4 = 0x08; 37 | public const uint ELEMENT_TYPE_U4 = 0x09; 38 | public const uint ELEMENT_TYPE_I8 = 0x0a; 39 | public const uint ELEMENT_TYPE_U8 = 0x0b; 40 | public const uint ELEMENT_TYPE_R4 = 0x0c; 41 | public const uint ELEMENT_TYPE_R8 = 0x0d; 42 | public const uint ELEMENT_TYPE_STRING = 0x0e; 43 | 44 | public const uint ELEMENT_TYPE_PTR = 0x0f; // PTR 45 | public const uint ELEMENT_TYPE_BYREF = 0x10; // BYREF 46 | 47 | public const uint ELEMENT_TYPE_VALUETYPE = 0x11; // VALUETYPE 48 | public const uint ELEMENT_TYPE_CLASS = 0x12; // CLASS 49 | 50 | public static Type GetClrTypeFromCorType(uint type) 51 | { 52 | switch (type) 53 | { 54 | case ELEMENT_TYPE_BOOLEAN: 55 | return typeof(bool); 56 | case ELEMENT_TYPE_CHAR: 57 | return typeof(char); 58 | case ELEMENT_TYPE_I1: 59 | return typeof(sbyte); 60 | case ELEMENT_TYPE_U1: 61 | return typeof(byte); 62 | case ELEMENT_TYPE_I2: 63 | return typeof(short); 64 | case ELEMENT_TYPE_U2: 65 | return typeof(ushort); 66 | case ELEMENT_TYPE_I4: 67 | return typeof(int); 68 | case ELEMENT_TYPE_U4: 69 | return typeof(uint); 70 | case ELEMENT_TYPE_I8: 71 | return typeof(long); 72 | case ELEMENT_TYPE_U8: 73 | return typeof(ulong); 74 | case ELEMENT_TYPE_STRING: 75 | return typeof(string); 76 | case ELEMENT_TYPE_CLASS: 77 | return typeof(object); 78 | default: 79 | return null; 80 | } 81 | 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /SDbgExt/DumpDictionary.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include 21 | 22 | void GetObjectString(WinDbgInterfaces *dbg, CLRDATA_ADDRESS addr, CStringW *str, CLRDATA_ADDRESS *typeMT) 23 | { 24 | ClrObjectData od = {}; 25 | if (FAILED(dbg->XCLR->GetObjectData(addr, &od))) 26 | { 27 | return; 28 | } 29 | 30 | *typeMT = od.MethodTable; 31 | 32 | if (od.ObjectType == OBJ_STRING) 33 | { 34 | UINT cchChars = 0; 35 | dbg->XCLR->GetObjectStringData(addr, 0, nullptr, &cchChars); 36 | 37 | if (cchChars > 0x200000 || cchChars == 0) 38 | return; 39 | 40 | auto buffer = str->GetBuffer(cchChars); 41 | if (SUCCEEDED(dbg->XCLR->GetObjectStringData(addr, cchChars, buffer, nullptr))) 42 | { 43 | str->ReleaseBufferSetLength(cchChars); 44 | } 45 | else 46 | { 47 | str->ReleaseBufferSetLength(0); 48 | } 49 | } 50 | } 51 | 52 | void EnumDctCallback(DctEntry ent, WinDbgInterfaces *dbg) 53 | { 54 | UNREFERENCED_PARAMETER(ent); 55 | UNREFERENCED_PARAMETER(dbg); 56 | 57 | const LPWSTR strFormat = L" [\"%s\"]"; 58 | 59 | CStringW key, value; 60 | CLRDATA_ADDRESS keyType = 0, valueType = 0; 61 | 62 | GetObjectString(dbg, ent.KeyPtr, &key, &keyType); 63 | GetObjectString(dbg, ent.ValuePtr, &value, &valueType); 64 | 65 | dwdprintf(dbg->Control, L"entry at:\t0x%p\r\nkey: \t0x%p", ent.EntryPtr, ent.KeyPtr); 66 | 67 | if (key.GetLength() > 0) 68 | { 69 | dwdprintf(dbg->Control, strFormat, key); 70 | } 71 | 72 | dwdprintf(dbg->Control, L"\r\nvalue:\t0x%p", ent.ValuePtr); 73 | if (value.GetLength() > 0) 74 | { 75 | dwdprintf(dbg->Control, strFormat, value); 76 | } 77 | 78 | dwdprintf(dbg->Control, L"\r\nhashCode:\t0x%08x\r\n\r\n", ent.HashCode); 79 | } 80 | 81 | DBG_FUNC(dumpdictionary) 82 | { 83 | DBG_PREAMBLE; 84 | UNREFERENCED_PARAMETER(hr); 85 | 86 | auto tokens = SPT::Util::Tokenize(args); 87 | BOOL shortMode = FALSE; 88 | ULONG64 objAddr = 0; 89 | 90 | for(size_t a = 0; a < tokens.size(); a++) 91 | { 92 | if (tokens[a].CompareNoCase("-short") == 0) 93 | { 94 | shortMode = TRUE; 95 | } 96 | else 97 | { 98 | objAddr = GetExpression(tokens[a]); 99 | } 100 | } 101 | 102 | auto cb = [&dbg](DctEntry ent)->BOOL { 103 | EnumDctCallback(ent, &dbg); 104 | return TRUE; 105 | }; 106 | 107 | CComObject adapt; 108 | adapt.Init(cb); 109 | 110 | hr = dbg.Ext->EnumHashtable(objAddr, &adapt); 111 | if (hr == E_INVALIDARG) 112 | { 113 | dwdprintf(dbg.Control, L"Object was not a known hashtable type\r\n"); 114 | } 115 | else if (FAILED(hr)) 116 | { 117 | dwdprintf(dbg.Control, L"Error reading object\r\n"); 118 | } 119 | 120 | return S_OK; 121 | } -------------------------------------------------------------------------------- /SDbgM/MDbgScriptForm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.ComponentModel; 21 | using System.Data; 22 | using System.Drawing; 23 | using System.Dynamic; 24 | using System.Linq; 25 | using System.Runtime.InteropServices; 26 | using System.Text; 27 | using System.Threading.Tasks; 28 | using System.Windows.Forms; 29 | using IronRuby; 30 | using Microsoft.Scripting.Hosting; 31 | 32 | namespace SPT.Managed 33 | { 34 | internal partial class MDbgScriptForm : Form 35 | { 36 | private SptWrapper _ext; 37 | private ScriptEngine _host; 38 | private ScriptScope _scope; 39 | 40 | private class Environment 41 | { 42 | private MDbgScriptForm _form; 43 | public Environment(MDbgScriptForm form) 44 | { 45 | _form = form; 46 | } 47 | 48 | public void OutputLocal(object text) 49 | { 50 | _form.txtResults.Text += text.ToString() + "\r\n"; 51 | } 52 | 53 | public void Output(object text) 54 | { 55 | _form._ext.DbgOutput(text.ToString() + "\r\n"); 56 | } 57 | } 58 | 59 | public MDbgScriptForm(SptWrapper ext) 60 | { 61 | _host = Ruby.CreateEngine(); 62 | 63 | _scope = _host.CreateScope(); 64 | _scope.SetVariable("ext", ext); 65 | _scope.SetVariable("dbg", new Environment(this)); 66 | 67 | _ext = ext; 68 | InitializeComponent(); 69 | } 70 | 71 | private void AddText(string text) 72 | { 73 | txtResults.Text += text + "\r\n"; 74 | txtResults.Select(txtResults.Text.Length - 1, 0); 75 | txtResults.ScrollToCaret(); 76 | } 77 | 78 | private void btExecute_Click(object sender, EventArgs e) 79 | { 80 | string code = txtCmd.Text.Trim(); 81 | ScriptSource source = _host.CreateScriptSourceFromString(code, Microsoft.Scripting.SourceCodeKind.AutoDetect); 82 | 83 | try 84 | { 85 | AddText("> " + code); 86 | var ret = source.Execute(_scope); 87 | if (ret != null) 88 | { 89 | AddText(ret.ToString()); 90 | } 91 | txtCmd.Text = ""; 92 | } 93 | catch (Exception ex) 94 | { 95 | AddText(ex.ToString()); 96 | } 97 | 98 | } 99 | 100 | protected override void OnClosed(EventArgs e) 101 | { 102 | _ext.Dispose(); 103 | 104 | base.OnClosed(e); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /SDbgExt/DbgEngCLRDataTarget.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "stdafx.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | class DbgEngCLRDataTarget : 27 | public CComObjectRoot, 28 | public ICLRDataTarget 29 | { 30 | public: 31 | 32 | BEGIN_COM_MAP(DbgEngCLRDataTarget) 33 | COM_INTERFACE_ENTRY(ICLRDataTarget) 34 | END_COM_MAP() 35 | 36 | void Init(IDebugSymbols3 *sym, IDebugDataSpaces *ds, IDebugSystemObjects *sysobj) 37 | { 38 | m_pDs = ds; 39 | m_pSym = sym; 40 | m_sysobj = sysobj; 41 | } 42 | 43 | HRESULT STDMETHODCALLTYPE GetMachineType( 44 | /* [out] */ ULONG32 *machineType); 45 | 46 | HRESULT STDMETHODCALLTYPE GetPointerSize( 47 | /* [out] */ ULONG32 *pointerSize); 48 | 49 | HRESULT STDMETHODCALLTYPE GetImageBase( 50 | /* [string][in] */ LPCWSTR imagePath, 51 | /* [out] */ CLRDATA_ADDRESS *baseAddress); 52 | 53 | HRESULT STDMETHODCALLTYPE ReadVirtual( 54 | /* [in] */ CLRDATA_ADDRESS address, 55 | /* [length_is][size_is][out] */ BYTE *buffer, 56 | /* [in] */ ULONG32 bytesRequested, 57 | /* [out] */ ULONG32 *bytesRead); 58 | 59 | HRESULT STDMETHODCALLTYPE WriteVirtual( 60 | /* [in] */ CLRDATA_ADDRESS address, 61 | /* [size_is][in] */ BYTE *buffer, 62 | /* [in] */ ULONG32 bytesRequested, 63 | /* [out] */ ULONG32 *bytesWritten); 64 | 65 | HRESULT STDMETHODCALLTYPE GetTLSValue( 66 | /* [in] */ ULONG32 threadID, 67 | /* [in] */ ULONG32 index, 68 | /* [out] */ CLRDATA_ADDRESS *value); 69 | 70 | HRESULT STDMETHODCALLTYPE SetTLSValue( 71 | /* [in] */ ULONG32 threadID, 72 | /* [in] */ ULONG32 index, 73 | /* [in] */ CLRDATA_ADDRESS value); 74 | 75 | HRESULT STDMETHODCALLTYPE GetCurrentThreadID( 76 | /* [out] */ ULONG32 *threadID); 77 | 78 | HRESULT STDMETHODCALLTYPE GetThreadContext( 79 | /* [in] */ ULONG32 threadID, 80 | /* [in] */ ULONG32 contextFlags, 81 | /* [in] */ ULONG32 contextSize, 82 | /* [size_is][out] */ BYTE *context); 83 | 84 | HRESULT STDMETHODCALLTYPE SetThreadContext( 85 | /* [in] */ ULONG32 threadID, 86 | /* [in] */ ULONG32 contextSize, 87 | /* [size_is][in] */ BYTE *context); 88 | 89 | HRESULT STDMETHODCALLTYPE Request( 90 | /* [in] */ ULONG32 reqCode, 91 | /* [in] */ ULONG32 inBufferSize, 92 | /* [size_is][in] */ BYTE *inBuffer, 93 | /* [in] */ ULONG32 outBufferSize, 94 | /* [size_is][out] */ BYTE *outBuffer); 95 | 96 | private: 97 | ULONG64 GetModuleAddress(LPCWSTR moduleName); 98 | 99 | CComPtr m_pSym; 100 | CComPtr m_pDs; 101 | CComPtr m_sysobj; 102 | }; -------------------------------------------------------------------------------- /SDbgExt/DumpSqlConnectionPools.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | 21 | class DumpPoolCallbacks : 22 | public CComObjectRoot, 23 | public IEnumSqlConnectionPoolsCallback 24 | { 25 | BEGIN_COM_MAP(DumpPoolCallbacks) 26 | COM_INTERFACE_ENTRY(IEnumSqlConnectionPoolsCallback) 27 | END_COM_MAP() 28 | 29 | public: 30 | 31 | DumpPoolCallbacks() 32 | : m_f(0), m_c(0) 33 | { 34 | } 35 | 36 | void Init(WinDbgInterfaces *dbg) 37 | { 38 | m_dbg = dbg; 39 | } 40 | 41 | STDMETHODIMP OnFactory (CLRDATA_ADDRESS factory ) 42 | { 43 | dwdprintf(m_dbg->Control, L"[%d] Factory @ %p\r\n", m_f++, factory, factory); 44 | return S_OK; 45 | } 46 | STDMETHODIMP OnPoolGroup (LPWSTR connString, CLRDATA_ADDRESS poolGroup) 47 | { 48 | dwdprintf(m_dbg->Control, L" - Connection String: %s\r\n - PoolGroup:\t%p\r\n", connString, poolGroup, poolGroup); 49 | return S_OK; 50 | } 51 | 52 | STDMETHODIMP OnPool(CLRDATA_ADDRESS pool, LPWSTR sid, UINT state, UINT waitCount, UINT totalObjects) 53 | { 54 | dwdprintf(m_dbg->Control, L"\tSID: %s\r\n\tPool: %p, State: %d, Waiters: %d, Size: %d\r\n", sid, pool, pool, state, waitCount, totalObjects); 55 | m_c = 0; 56 | return S_OK; 57 | } 58 | 59 | STDMETHODIMP OnConnection(CLRDATA_ADDRESS conn, UINT32 state, ClrDateTime createTime, UINT32 pooledCount, LONG isOpen, UINT32 asyncCommandCount, CLRDATA_ADDRESS cmd, LPWSTR cmdText, UINT32 timeout) 60 | { 61 | UNREFERENCED_PARAMETER(isOpen); 62 | UNREFERENCED_PARAMETER(pooledCount); 63 | 64 | if (m_c == 0) 65 | { 66 | dwdprintf(m_dbg->Control, L"\tConnections:\r\n\t\t ConnPtr State #Async Created Command/Reader Timeout Text\r\n"); 67 | } 68 | 69 | WCHAR createTimeStr[25] = { 0 }; 70 | m_dbg->Process->FormatDateTime(createTime.Ticks, ARRAYSIZE(createTimeStr), createTimeStr); 71 | 72 | dwdprintf(m_dbg->Control, L"\t\t[%03x] %016p %01d %01d %20s", m_c++, conn, conn, state, asyncCommandCount, createTimeStr); 73 | if (cmd) 74 | { 75 | dwdprintf(m_dbg->Control, L" %016p %3d %Y{t}", cmd, cmd, timeout, cmdText); 76 | } 77 | dwdprintf(m_dbg->Control, L"\r\n"); 78 | return S_OK; 79 | } 80 | private: 81 | WinDbgInterfaces *m_dbg; 82 | int m_f; 83 | int m_c; 84 | }; 85 | 86 | DBG_FUNC(dumpsqlconnectionpools) 87 | { 88 | DBG_PREAMBLE; 89 | UNREFERENCED_PARAMETER(args); 90 | 91 | CComPtr cbPtr; 92 | CComObject *cb; 93 | CComObject::CreateInstance(&cb); 94 | cbPtr = cb; 95 | cbPtr->Init(&dbg); 96 | 97 | 98 | hr = dbg.Ext->EnumSqlConnectionPools(cbPtr, NULL); 99 | 100 | return hr; 101 | } 102 | 103 | DBG_FUNC(sqlblame) 104 | { 105 | return dumpsqlconnectionpools(clientPtr, args); 106 | } -------------------------------------------------------------------------------- /SDbgExt/WinDbgTableFormatter.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "stdafx.h" 20 | #include "WinDbgExt.h" 21 | #include 22 | #include 23 | #include 24 | 25 | class WinDbgTableFormatter 26 | { 27 | public: 28 | WinDbgTableFormatter(IDebugControl4 *ctrl) 29 | : m_ctrl(ctrl), m_currColumn(0) 30 | { 31 | } 32 | 33 | void Reset() 34 | { 35 | m_columns.clear(); 36 | m_currColumn = 0; 37 | } 38 | 39 | void AddPointerColumn(WCHAR *title) 40 | { 41 | UNREFERENCED_PARAMETER(title); 42 | AddColumn(title, sizeof(void*) * 2); 43 | } 44 | 45 | void AddColumn(WCHAR *title, int width, BOOL alignLeft = FALSE, WCHAR seperator = L' ') 46 | { 47 | UNREFERENCED_PARAMETER(title); 48 | m_columns.push_back(_Column(width, seperator, title, alignLeft)); 49 | } 50 | 51 | WinDbgTableFormatter *Column(WCHAR *format, ...) 52 | { 53 | _Column col = m_columns[m_currColumn++]; 54 | int width = col.Width; 55 | 56 | va_list argPtr; 57 | va_start(argPtr, format); 58 | 59 | if (width == -1) 60 | { 61 | m_ctrl->ControlledOutputVaListWide(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, argPtr); 62 | } 63 | else 64 | { 65 | int chars = _vscwprintf(format, argPtr); 66 | std::vector buffer(chars + sizeof(WCHAR)); 67 | WCHAR *bufferPtr = buffer.data(); 68 | 69 | vswprintf_s(bufferPtr, buffer.size(), format, argPtr); 70 | 71 | std::wstring newStr(buffer.data()); 72 | if (wcscmp(L"%lld", format) == 0 && width < chars) 73 | { 74 | } 75 | else if (chars > width ) 76 | { 77 | newStr = newStr.substr(newStr.length() - (width - 3)); 78 | newStr = L"..." + newStr; 79 | } 80 | else if (chars < width) 81 | { 82 | if (col.AlignLeft) 83 | { 84 | newStr = newStr + std::wstring(width - chars, L' '); 85 | } 86 | else 87 | { 88 | newStr = std::wstring(width - chars, L' ') + newStr; 89 | } 90 | } 91 | 92 | dwdprintf(m_ctrl, L"%s ", newStr.c_str()); 93 | } 94 | va_end(argPtr); 95 | return this; 96 | } 97 | 98 | WinDbgTableFormatter *NewRow() 99 | { 100 | dwdprintf(m_ctrl, L"\r\n"); 101 | m_currColumn = 0; 102 | 103 | return this; 104 | } 105 | 106 | void PrintHeader() 107 | { 108 | std::for_each(m_columns.begin(), m_columns.end(), [this](_Column c) -> void { 109 | std::wstringstream ss; 110 | ss << L"%" << c.Width << L"s "; 111 | 112 | dwdprintf(m_ctrl, ss.str().c_str(), c.Title); 113 | }); 114 | 115 | dwdprintf(m_ctrl, L"\r\n"); 116 | } 117 | 118 | private: 119 | 120 | struct _Column 121 | { 122 | _Column(int w, WCHAR s, WCHAR *title, BOOL alignLeft) 123 | : Width(w), Seperator(s), Title(title), AlignLeft(alignLeft) 124 | { } 125 | 126 | int Width; 127 | WCHAR Seperator; 128 | WCHAR *Title; 129 | BOOL AlignLeft; 130 | }; 131 | 132 | int m_currColumn; 133 | std::vector<_Column> m_columns; 134 | CComPtr m_ctrl; 135 | }; -------------------------------------------------------------------------------- /SDbgExt/SDbgExt_EnumStackObjects.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include 21 | #include 22 | #include "..\SDbgCore\inc\EnumAdaptors.h" 23 | 24 | HRESULT CSDbgExt::EnumStackObjects(DWORD corThreadId, IEnumObjectsCallback *cb) 25 | { 26 | CComPtr cbPtr(cb); 27 | CLRDATA_ADDRESS threadObj = 0; 28 | HRESULT hr = S_OK; 29 | RETURN_IF_FAILED(m_proc->FindThreadByCorThreadId(corThreadId, &threadObj)); 30 | 31 | return EnumStackObjectsByThreadObj(threadObj, cbPtr); 32 | } 33 | 34 | HRESULT CSDbgExt::EnumStackObjectsByThreadObj(CLRDATA_ADDRESS threadObj, IEnumObjectsCallback *cb) 35 | { 36 | CComPtr dac; 37 | CComPtr dcma; 38 | 39 | m_proc->GetCorDataAccess(&dac); 40 | m_proc->GetMemoryAccess(&dcma); 41 | 42 | ClrThreadData td = {}; 43 | HRESULT hr = S_OK; 44 | RETURN_IF_FAILED(dac->GetThreadData(threadObj, &td)); 45 | 46 | CLRDATA_ADDRESS stackBase = 0, stackLimit = 0; 47 | RETURN_IF_FAILED(dcma->GetThreadStack(td.osThreadId, &stackBase, &stackLimit)); 48 | 49 | return EnumStackObjectsByStackParams(stackBase, stackLimit, cb); 50 | 51 | } 52 | HRESULT CSDbgExt::EnumStackObjectsByStackParams(CLRDATA_ADDRESS stackBase, CLRDATA_ADDRESS stackLimit, IEnumObjectsCallback *cb) 53 | { 54 | HRESULT hr = S_OK; 55 | 56 | CComPtr cbPtr(cb); 57 | CComPtr dac; 58 | CComPtr dcma; 59 | 60 | m_proc->GetCorDataAccess(&dac); 61 | m_proc->GetMemoryAccess(&dcma); 62 | 63 | auto cbWrapper = GetObjectEnumCallback(cbPtr); 64 | 65 | struct AddrRange 66 | { 67 | CLRDATA_ADDRESS Begin; 68 | CLRDATA_ADDRESS End; 69 | }; 70 | 71 | std::vector ranges; 72 | auto buildHeapSnapshotCb = [&ranges](ClrGcHeapSegmentData segData)->BOOL { 73 | AddrRange range = { segData.AllocBegin, segData.Allocated }; 74 | ranges.push_back(range); 75 | 76 | return TRUE; 77 | }; 78 | 79 | CComObject adapt; 80 | adapt.Init(buildHeapSnapshotCb); 81 | RETURN_IF_FAILED(m_proc->EnumHeapSegments(&adapt)); 82 | 83 | for (CLRDATA_ADDRESS addr = stackLimit; addr < stackBase; addr += sizeof(void*)) 84 | { 85 | CLRDATA_ADDRESS stackPtr = 0; 86 | if (SUCCEEDED(dcma->ReadVirtual(addr, &stackPtr, sizeof(void*), NULL)) && stackPtr != 0) 87 | { 88 | if (std::any_of(ranges.cbegin(), ranges.cend(), [stackPtr](const AddrRange r)->bool { 89 | return stackPtr >= r.Begin && stackPtr <= r.End; 90 | })) 91 | { 92 | if (m_proc->IsValidObject(stackPtr)) 93 | { 94 | ClrObjectData od = {}; 95 | dac->GetObjectData(stackPtr, &od); 96 | od.ObjectAddress = stackPtr; 97 | od.Reserved = addr; 98 | if (FAILED(cbWrapper(od, FALSE))) 99 | { 100 | return S_FALSE; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | ClrObjectData junk = {}; 108 | cbWrapper(junk, TRUE); 109 | 110 | return S_OK; 111 | } -------------------------------------------------------------------------------- /SDbgM/Util/UsefulGlobals.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using SPT.Managed.ClrObjects; 24 | 25 | namespace SPT.Managed.Util 26 | { 27 | internal static class UsefulGlobals 28 | { 29 | private static Dictionary s_usefulMethodTables = null; 30 | private static Dictionary s_usefulMethodTablesInverse = null; 31 | private static readonly HashSet s_primitives = new HashSet() 32 | { 33 | typeof(Boolean), typeof(Char), 34 | typeof(Byte), typeof(SByte), 35 | typeof(Int16), typeof(UInt16), 36 | typeof(Int32), typeof(UInt32), 37 | typeof(Int64), typeof(UInt64), 38 | typeof(Single), typeof(Double), typeof(Decimal), 39 | typeof(String), typeof(DateTime) 40 | }; 41 | 42 | private static Dictionary s_corFieldType = new Dictionary() 43 | { 44 | { CorType.ELEMENT_TYPE_BOOLEAN, typeof(Boolean) }, 45 | { CorType.ELEMENT_TYPE_CHAR, typeof(Char) }, 46 | 47 | { CorType.ELEMENT_TYPE_I1, typeof(Byte) }, 48 | { CorType.ELEMENT_TYPE_U1, typeof(SByte) }, 49 | 50 | { CorType.ELEMENT_TYPE_I2, typeof(Int16) }, 51 | { CorType.ELEMENT_TYPE_U2, typeof(UInt16) }, 52 | 53 | { CorType.ELEMENT_TYPE_I4, typeof(Int32) }, 54 | { CorType.ELEMENT_TYPE_U4, typeof(UInt32) }, 55 | 56 | { CorType.ELEMENT_TYPE_I8, typeof(Int64) }, 57 | { CorType.ELEMENT_TYPE_U8, typeof(UInt64) }, 58 | 59 | { CorType.ELEMENT_TYPE_STRING, typeof(String) }, 60 | { CorType.ELEMENT_TYPE_CLASS, typeof(Object) } 61 | }; 62 | 63 | public static void EnsureInit(SptWrapper wrapper) 64 | { 65 | if (s_usefulMethodTables == null) 66 | { 67 | InitMethodTables(wrapper); 68 | } 69 | } 70 | 71 | private static void InitMethodTables(SptWrapper wrapper) 72 | { 73 | s_usefulMethodTables = new Dictionary(); 74 | s_usefulMethodTablesInverse = new Dictionary(); 75 | 76 | foreach (var type in s_primitives) 77 | { 78 | var typeMt = wrapper.Proc.FindTypeByName("mscorlib.dll", type.FullName); 79 | s_usefulMethodTables.Add(typeMt, type); 80 | s_usefulMethodTablesInverse.Add(type, typeMt); 81 | } 82 | } 83 | 84 | 85 | public static Dictionary MethodTableToType { get { return s_usefulMethodTables; } } 86 | public static Dictionary TypeToMethodTable { get { return s_usefulMethodTablesInverse; } } 87 | public static Dictionary CorFieldTypeToType { get { return s_corFieldType; } } 88 | public static HashSet Primitives { get { return s_primitives; } } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /SDbgM/MDbgScriptForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SPT.Managed 2 | { 3 | partial class MDbgScriptForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btExecute = new System.Windows.Forms.Button(); 32 | this.txtCmd = new System.Windows.Forms.TextBox(); 33 | this.txtResults = new System.Windows.Forms.TextBox(); 34 | this.SuspendLayout(); 35 | // 36 | // btExecute 37 | // 38 | this.btExecute.Location = new System.Drawing.Point(451, 452); 39 | this.btExecute.Name = "btExecute"; 40 | this.btExecute.Size = new System.Drawing.Size(75, 23); 41 | this.btExecute.TabIndex = 0; 42 | this.btExecute.Text = "Execute"; 43 | this.btExecute.UseVisualStyleBackColor = true; 44 | this.btExecute.Click += new System.EventHandler(this.btExecute_Click); 45 | // 46 | // txtCmd 47 | // 48 | this.txtCmd.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 49 | this.txtCmd.Location = new System.Drawing.Point(12, 452); 50 | this.txtCmd.Name = "txtCmd"; 51 | this.txtCmd.Size = new System.Drawing.Size(433, 22); 52 | this.txtCmd.TabIndex = 0; 53 | // 54 | // txtResults 55 | // 56 | this.txtResults.Font = new System.Drawing.Font("Courier New", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 57 | this.txtResults.Location = new System.Drawing.Point(12, 12); 58 | this.txtResults.MaxLength = 0; 59 | this.txtResults.Multiline = true; 60 | this.txtResults.Name = "txtResults"; 61 | this.txtResults.ScrollBars = System.Windows.Forms.ScrollBars.Both; 62 | this.txtResults.Size = new System.Drawing.Size(514, 431); 63 | this.txtResults.TabIndex = 2; 64 | // 65 | // MDbgScriptForm 66 | // 67 | this.AcceptButton = this.btExecute; 68 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 69 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 70 | this.ClientSize = new System.Drawing.Size(536, 484); 71 | this.Controls.Add(this.txtResults); 72 | this.Controls.Add(this.txtCmd); 73 | this.Controls.Add(this.btExecute); 74 | this.Name = "MDbgScriptForm"; 75 | this.Text = "SDbg Script"; 76 | this.ResumeLayout(false); 77 | this.PerformLayout(); 78 | 79 | } 80 | 81 | #endregion 82 | 83 | private System.Windows.Forms.Button btExecute; 84 | private System.Windows.Forms.TextBox txtCmd; 85 | private System.Windows.Forms.TextBox txtResults; 86 | } 87 | } -------------------------------------------------------------------------------- /SDbgExt/DumpMT.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | #include "..\SDbgCore\inc\ClrObject.h" 21 | #include 22 | #include 23 | #include "WinDbgTableFormatter.h" 24 | 25 | DBG_FUNC(dumpmt) 26 | { 27 | DBG_PREAMBLE; 28 | UNREFERENCED_PARAMETER(hr); 29 | 30 | auto tokens = SPT::Util::Tokenize(args); 31 | if (tokens.size() == 0 || tokens.size() > 2) 32 | { 33 | dwdprintf(dbg.Control, L"Usage: !dumpmt [-MD] [MT address]"); 34 | return E_INVALIDARG; 35 | } 36 | 37 | BOOL dumpMDs = (tokens.size() == 2 && _stricmp(tokens[0], "-MD") == 0); 38 | CLRDATA_ADDRESS mtAddr = GetExpression(tokens[tokens.size() - 1]); 39 | 40 | ClrMethodTableData mtd = {}; 41 | if (FAILED(dbg.XCLR->GetMethodTableData(mtAddr, &mtd))) 42 | { 43 | dwdprintf(dbg.Control, L"%p is not a MethodTable.\r\n", mtAddr); 44 | return E_INVALIDARG; 45 | } 46 | 47 | 48 | WCHAR buffer[512]; 49 | UINT len; 50 | dbg.XCLR->GetMethodTableName(mtAddr, ARRAYSIZE(buffer), buffer, &len); 51 | 52 | WinDbgTableFormatter tf(dbg.Control); 53 | tf.AddColumn(L"Name", 16, TRUE); 54 | tf.AddColumn(L"Value", -1); 55 | 56 | tf 57 | .Column(L"EEClass:")->Column(L"0x%p", mtd.EEClass)->NewRow() 58 | ->Column(L"Module:")->Column(L"0x%p")->NewRow() 59 | ->Column(L"Name:")->Column(L"%s", buffer)->NewRow() 60 | ->Column(L"mdToken:")->Column(L"0x%08x", mtd.mdToken)->NewRow(); 61 | 62 | GetModuleName(dbg.XCLR, mtd.Module, buffer); 63 | 64 | tf.Column(L"File:")->Column(L"%s", buffer)->NewRow() 65 | ->Column(L"BaseSize:")->Column(L"0x%x", mtd.BaseSize)->NewRow() 66 | ->Column(L"ComponentSize:")->Column(L"0x%x", mtd.ComponentSize)->NewRow() 67 | ->Column(L"Slots in VTable:")->Column(L"%d", mtd.NumSlotsInVTable)->NewRow(); 68 | 69 | dwdprintf(dbg.Control, L"Number of IFaces in IFaceMap: %d\r\n", mtd.NumInterfaces); 70 | 71 | if (!dumpMDs) 72 | return S_OK; 73 | 74 | dwdprintf(dbg.Control, L"--------------------------------------\r\n"); 75 | dwdprintf(dbg.Control, L"MethodDesc Table\r\n"); 76 | 77 | tf.Reset(); 78 | tf.AddPointerColumn(L"Entry"); 79 | tf.AddPointerColumn(L"MethodDesc"); 80 | tf.AddColumn(L"JIT", 6); 81 | tf.AddColumn(L"Name", -1); 82 | 83 | tf.Column(L"Entry")->Column(L"MethodDe")->Column(L"JIT")->Column(L"Name")->NewRow(); 84 | 85 | for (UINT i = 0; i < mtd.NumSlotsInVTable; i++) 86 | { 87 | CLRDATA_ADDRESS entryAddr; 88 | ClrCodeHeaderData chd = {}; 89 | if (SUCCEEDED(dbg.XCLR->GetMethodTableSlot(mtAddr, i, &entryAddr)) 90 | && SUCCEEDED(dbg.XCLR->GetCodeHeaderData(entryAddr, &chd))) 91 | { 92 | dbg.XCLR->GetMethodDescName(chd.methodDescPtr, ARRAYSIZE(buffer), buffer, &len); 93 | 94 | WCHAR *jitType; 95 | switch (chd.JITType) 96 | { 97 | case JITTypes::TYPE_EJIT: 98 | jitType = L"PreJIT"; 99 | break; 100 | case JITTypes::TYPE_JIT: 101 | jitType = L"JIT"; 102 | break; 103 | case JITTypes::TYPE_UNKNOWN: 104 | jitType = L"NONE"; 105 | break; 106 | } 107 | 108 | tf.Column(L"%p", entryAddr)->Column(L"%p", chd.methodDescPtr)->Column(L"%6s", jitType)->Column(L"%s", buffer)->NewRow(); 109 | } 110 | } 111 | return S_OK; 112 | } 113 | -------------------------------------------------------------------------------- /SDbgM/Util/SuperBitConverter.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | 24 | namespace SPT.Managed.Util 25 | { 26 | public static class SuperBitConverter 27 | { 28 | public static ulong ToPointer(byte[] data) 29 | { 30 | if (data.Length != 4 && data.Length != 8) 31 | { 32 | throw new InvalidOperationException("Invalid data size"); 33 | } 34 | 35 | if (data.Length == 4) 36 | { 37 | Array.Resize(ref data, 8); 38 | } 39 | return BitConverter.ToUInt64(data, 0); 40 | } 41 | 42 | public static object Convert(byte[] data, Type target) 43 | { 44 | if (UsefulGlobals.Primitives.Contains(target)) 45 | { 46 | if (target == typeof(Boolean)) 47 | { 48 | return BitConverter.ToBoolean(data, 0); 49 | } 50 | else if (target == typeof(Char)) 51 | { 52 | return BitConverter.ToChar(data, 0); 53 | } 54 | else if (target == typeof(Byte)) 55 | { 56 | return data[0]; 57 | } 58 | else if (target == typeof(SByte)) 59 | { 60 | return (SByte)data[0]; 61 | } 62 | else if (target == typeof(Int16)) 63 | { 64 | return BitConverter.ToInt16(data, 0); 65 | } 66 | else if (target == typeof(UInt16)) 67 | { 68 | return BitConverter.ToUInt16(data, 0); 69 | } 70 | else if (target == typeof(Int32)) 71 | { 72 | return BitConverter.ToInt32(data, 0); 73 | } 74 | else if (target == typeof(UInt32)) 75 | { 76 | return BitConverter.ToUInt32(data, 0); 77 | } 78 | else if (target == typeof(Int64)) 79 | { 80 | return BitConverter.ToInt64(data, 0); 81 | } 82 | else if (target == typeof(UInt64)) 83 | { 84 | return BitConverter.ToUInt64(data, 0); 85 | } 86 | else if (target == typeof(Single)) 87 | { 88 | return BitConverter.ToSingle(data, 0); 89 | } 90 | else if (target == typeof(Double)) 91 | { 92 | return BitConverter.ToDouble(data, 0); 93 | } 94 | else 95 | { 96 | throw new NotSupportedException(); 97 | } 98 | } 99 | else 100 | { 101 | if (data.Length != 8) 102 | { 103 | Array.Resize(ref data, 8); 104 | } 105 | return BitConverter.ToInt64(data, 0); 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /SDbgM/UMThunk.cs: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | using SPT.Managed.WinDbg; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading; 24 | using System.Threading.Tasks; 25 | using System.Windows.Forms; 26 | 27 | namespace SPT.Managed 28 | { 29 | internal class UMThunk 30 | { 31 | public static int InitHost(string arg) 32 | { 33 | Thread.CurrentThread.SetApartmentState(ApartmentState.STA); 34 | 35 | var args = arg.Split('|').ToArray(); 36 | 37 | string opCode = args[0]; 38 | string extAddr = args[1]; 39 | 40 | args = args.Skip(2).ToArray(); 41 | 42 | // Show script form 43 | if (opCode == "0") 44 | { 45 | arg = string.Join("|", args); 46 | 47 | ManualResetEvent initComplete = new ManualResetEvent(false); 48 | var t = RunOnNetSTAThread(() => 49 | { 50 | InitMDbgScriptForm(extAddr, args, initComplete); 51 | }); 52 | 53 | initComplete.WaitOne(); 54 | return 1; 55 | } 56 | // Run method stub in 57 | else if (opCode == "1") 58 | { 59 | string entryPoint = args[0]; 60 | 61 | if (args.Length > 1) 62 | { 63 | arg = args[1]; 64 | } 65 | else 66 | { 67 | arg = ""; 68 | } 69 | 70 | var entryStub = typeof(Stubs).GetMethod(entryPoint); 71 | if (entryPoint == null) 72 | return 1; 73 | 74 | //var t = RunOnNetSTAThread(() => 75 | //{ 76 | entryStub.Invoke(null, new object[] { GetSptWrapper(extAddr), arg }); 77 | //}); 78 | 79 | //t.Join(); 80 | 81 | return 1; 82 | } 83 | else 84 | { 85 | return 0; 86 | } 87 | } 88 | 89 | private static Thread RunOnNetSTAThread(ThreadStart threadStart) 90 | { 91 | ManualResetEvent initComplete = new ManualResetEvent(false); 92 | ThreadStart initMethod = threadStart; 93 | 94 | Thread t = new Thread(initMethod); 95 | t.SetApartmentState(ApartmentState.STA); 96 | t.Start(); 97 | 98 | return t; 99 | } 100 | 101 | private static void InitMDbgScriptForm(string extAddr, string[] args, ManualResetEvent initComplete) 102 | { 103 | var ext = GetSptWrapper(extAddr); 104 | 105 | MDbgScriptForm tf = new MDbgScriptForm(ext); 106 | tf.Show(); 107 | 108 | initComplete.Set(); 109 | 110 | Application.Run(tf); 111 | } 112 | 113 | private static SptWrapper GetSptWrapper(string addr) 114 | { 115 | var addrOfExtObject = ulong.Parse(addr); 116 | var ext = SptWrapper.CreateInProcess(addrOfExtObject); 117 | return ext; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /SDbgCore/inc/ClrObject.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #pragma once 19 | #include "stdafx.h" 20 | #include "ClrObjectArray.h" 21 | 22 | class ClrObject; 23 | typedef CComObject CClrObject; 24 | 25 | class ClrObject : 26 | public CComObjectRoot, 27 | public IClrObject 28 | { 29 | public: 30 | BEGIN_COM_MAP(ClrObject) 31 | COM_INTERFACE_ENTRY(IClrObject) 32 | END_COM_MAP() 33 | 34 | static IClrObject *Construct(IClrProcess *proc, CLRDATA_ADDRESS obj) 35 | { 36 | CClrObject *clrObj; 37 | CClrObject::CreateInstance(&clrObj); 38 | clrObj->AddRef(); 39 | clrObj->Init(proc, obj); 40 | 41 | return clrObj; 42 | } 43 | 44 | STDMETHODIMP_(LONG) IsValid() 45 | { 46 | return m_addr != NULL && m_proc->IsValidObject(m_addr); 47 | } 48 | 49 | STDMETHODIMP_(CLRDATA_ADDRESS) Address() 50 | { 51 | return m_addr; 52 | } 53 | 54 | STDMETHODIMP GetFieldValueAddr(LPWSTR field, CLRDATA_ADDRESS *ret) 55 | { 56 | return m_proc->GetFieldValuePtr(m_addr, field, ret); 57 | } 58 | 59 | STDMETHODIMP GetFieldValueObj(LPWSTR field, IClrObject **ret) 60 | { 61 | CLRDATA_ADDRESS addr = 0; 62 | HRESULT hr = S_OK; 63 | RETURN_IF_FAILED(m_proc->GetFieldValuePtr(m_addr, field, &addr)); 64 | 65 | CClrObject *obj; 66 | CClrObject::CreateInstance(&obj); 67 | obj->AddRef(); 68 | obj->Init(m_proc, addr); 69 | 70 | *ret = obj; 71 | return S_OK; 72 | } 73 | 74 | STDMETHODIMP GetFieldValueUInt32(LPWSTR field, UINT32 *val) 75 | { 76 | return m_proc->GetFieldValueBuffer(m_addr, field, sizeof(UINT32), (PVOID)val, NULL); 77 | } 78 | 79 | STDMETHODIMP GetFieldValueWSTR(LPWSTR field, ULONG32 iNumChars, LPWSTR buffer, PULONG bytesRead) 80 | { 81 | return m_proc->GetFieldValueString(m_addr, field, iNumChars, buffer, bytesRead); 82 | } 83 | 84 | STDMETHODIMP GetFieldValueArray(LPWSTR field, IClrObjectArray **ret) 85 | { 86 | HRESULT hr = S_OK; 87 | CLRDATA_ADDRESS arrayObj; 88 | RETURN_IF_FAILED(m_proc->GetFieldValuePtr(m_addr, field, &arrayObj)); 89 | 90 | *ret = ClrObjectArray::Construct(m_proc, arrayObj); 91 | return S_OK; 92 | } 93 | 94 | STDMETHODIMP GetTypeName(ULONG32 cchBuffer, LPWSTR buffer, PULONG nameLen) 95 | { 96 | HRESULT hr = S_OK; 97 | RETURN_IF_FAILED(EnsureMethodTable()); 98 | 99 | CComPtr dac; 100 | m_proc->GetCorDataAccess(&dac); 101 | return dac->GetMethodTableName(m_mtAddr, cchBuffer, buffer, (ULONG32*)nameLen); 102 | } 103 | 104 | STDMETHODIMP GetMethodTable(CLRDATA_ADDRESS *mt) 105 | { 106 | HRESULT hr; 107 | RETURN_IF_FAILED(EnsureMethodTable()); 108 | 109 | *mt = m_mtAddr; 110 | return S_OK; 111 | } 112 | 113 | protected: 114 | ClrObject() 115 | : m_mtAddr(0) 116 | { 117 | } 118 | 119 | private: 120 | void Init(IClrProcess *proc, CLRDATA_ADDRESS obj) 121 | { 122 | m_addr = obj; 123 | m_proc = proc; 124 | } 125 | 126 | HRESULT EnsureMethodTable() 127 | { 128 | HRESULT hr = S_OK; 129 | if (!m_mtAddr) 130 | { 131 | ClrObjectData od = {}; 132 | CComPtr dac; 133 | m_proc->GetCorDataAccess(&dac); 134 | RETURN_IF_FAILED(dac->GetObjectData(m_addr, &od)); 135 | 136 | m_mtAddr = od.MethodTable; 137 | } 138 | return hr; 139 | } 140 | 141 | CComPtr m_proc; 142 | CLRDATA_ADDRESS m_addr; 143 | CLRDATA_ADDRESS m_mtAddr; 144 | }; -------------------------------------------------------------------------------- /SDbgExt2Tests/DictionaryTests.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "TestCommon.h" 4 | #include 5 | 6 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 7 | 8 | namespace SDbgExt2Tests2 9 | { 10 | #ifndef _WIN64 11 | TEST_CLASS(DictionaryTests) 12 | { 13 | public: 14 | ADD_TEST_INIT(L"..\\dumps\\x86\\dct_1.dmp") 15 | 16 | TEST_METHOD(DumpDictionary_GenericDictionary) 17 | { 18 | DctEntry expected[] = 19 | #ifndef _WIN64 20 | { { 0x023c3fb0, 0x023c2418, 0x023c2424 }, { 0x023c3fc0, 0x023c24e4, 0x023c24f0 } }; 21 | #else 22 | { { 0, 0 } }; 23 | #endif 24 | DumpDictionary_TestImpl((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c2318, 0), 58, expected, ARRAYSIZE(expected)); 25 | } 26 | 27 | TEST_METHOD(DumpDictionary_Hashtable) 28 | { 29 | DctEntry expected[] = 30 | #ifndef _WIN64 31 | { { 0x023c33f0, 0x023c2b4c, 0x023c2b58 }, { 0x023c33fc, 0x023c2da4, 0x023c2db0 } }; 32 | #else 33 | { { 0, 0 } }; 34 | #endif 35 | DumpDictionary_TestImpl((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c23b4, 0), 58, expected, ARRAYSIZE(expected)); 36 | } 37 | 38 | TEST_METHOD(DumpDictionary_HybridDictionaryWithList) 39 | { 40 | DctEntry expected[] = 41 | #ifndef _WIN64 42 | { { 0x023c244c, 0x023c2418, 0x023c2424 }, { 0x023c24fc, 0x023c24e4, 0x023c24f0 } }; 43 | #else 44 | { { 0, 0 } }; 45 | #endif 46 | DumpDictionary_TestImpl((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c23a0, 0), 5, expected, ARRAYSIZE(expected)); 47 | } 48 | 49 | TEST_METHOD(DumpDictionary_HybridDictionaryWithDictionary) 50 | { 51 | DctEntry expected[] = 52 | #ifndef _WIN64 53 | { { 0x023c38d0, 0x023c45bc, 0x023c45c8 }, { 0x023c38dc, 0x023c29b0, 0x023c29bc } }; 54 | #else 55 | { { 0, 0 } }; 56 | #endif 57 | DumpDictionary_TestImpl((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c238c, 0), 58, expected, ARRAYSIZE(expected)); 58 | } 59 | 60 | TEST_METHOD(FindDctEntryByKey) 61 | { 62 | CLRDATA_ADDRESS addr; 63 | auto hr = ext->FindDctEntryByHash(BITNESS_CONDITIONAL(0x023c2318, 0), 1, &addr); 64 | 65 | ASSERT_SOK(hr); 66 | Assert::AreEqual((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x00000000023c2424, 0), addr); 67 | } 68 | 69 | class BulkDctEnumAdaptor 70 | : public CComObjectRoot 71 | , public IEnumHashtableBatchCallback 72 | { 73 | BEGIN_COM_MAP(BulkDctEnumAdaptor) 74 | COM_INTERFACE_ENTRY(IEnumHashtableBatchCallback) 75 | END_COM_MAP() 76 | 77 | public: 78 | BulkDctEnumAdaptor() 79 | : TotalEntries(0) 80 | {} 81 | 82 | STDMETHODIMP Callback(ULONG numEntries, DctEntry entries[]) 83 | { 84 | TotalEntries += numEntries; 85 | return S_OK; 86 | } 87 | 88 | STDMETHODIMP Callback(DctEntry entry) 89 | { 90 | return E_NOTIMPL; 91 | } 92 | 93 | ULONG TotalEntries; 94 | }; 95 | 96 | TEST_METHOD(DumpDictionary_Batch) 97 | { 98 | CComObject *adapt; 99 | CComObject::CreateInstance(&adapt); 100 | adapt->AddRef(); 101 | 102 | auto hr = ext->EnumHashtable((CLRDATA_ADDRESS)BITNESS_CONDITIONAL(0x023c2318, 0), adapt); 103 | 104 | ASSERT_SOK(hr); 105 | Assert::AreEqual((ULONG)58, adapt->TotalEntries); 106 | 107 | adapt->Release(); 108 | 109 | } 110 | 111 | void DumpDictionary_TestImpl(CLRDATA_ADDRESS dctAddr, size_t numEntriesExpected, DctEntry *expected, int countExpected) 112 | { 113 | int c = 0; 114 | std::vector entries; 115 | 116 | auto cb = [&entries](DctEntry entry)->BOOL { 117 | entries.push_back(entry); 118 | return TRUE; 119 | }; 120 | 121 | CComObject adapt; 122 | adapt.Init(cb); 123 | 124 | auto hr = ext->EnumHashtable(dctAddr, &adapt); 125 | 126 | ASSERT_SOK(hr); 127 | Assert::AreEqual((size_t)numEntriesExpected, entries.size()); 128 | for (int a = 0; a < countExpected; a++) 129 | { 130 | Assert::AreEqual(expected[a].EntryPtr, entries[a].EntryPtr); 131 | Assert::AreEqual(expected[a].KeyPtr, entries[a].KeyPtr); 132 | Assert::AreEqual(expected[a].ValuePtr, entries[a].ValuePtr); 133 | } 134 | } 135 | 136 | }; 137 | #endif 138 | } -------------------------------------------------------------------------------- /SDbgExt2.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDbgCore", "SDbgCore\SDbgCore.vcxproj", "{35663062-4DEC-49F9-BF5F-3C3E34828010}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPTTests", "SDbgExt2Tests\SDbgExt2Tests2.vcxproj", "{648A7B22-65ED-4418-8735-458C70576D59}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPT", "SDbgExt\SDbgExt.vcxproj", "{5F22CF78-8740-4419-B863-4628DCCFF1D2}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SPTMTests", "SDbgMTests\SPTMTests.csproj", "{C4B3F342-3734-4DE2-BC4F-2EF80CED3683}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SPTM", "SDbgM\SPTM.csproj", "{74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Win32 = Release|Win32 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Debug|Win32.Build.0 = Debug|Win32 24 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Debug|x64.ActiveCfg = Debug|x64 25 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Debug|x64.Build.0 = Debug|x64 26 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Release|Win32.ActiveCfg = Release|Win32 27 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Release|Win32.Build.0 = Release|Win32 28 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Release|x64.ActiveCfg = Release|x64 29 | {35663062-4DEC-49F9-BF5F-3C3E34828010}.Release|x64.Build.0 = Release|x64 30 | {648A7B22-65ED-4418-8735-458C70576D59}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {648A7B22-65ED-4418-8735-458C70576D59}.Debug|Win32.Build.0 = Debug|Win32 32 | {648A7B22-65ED-4418-8735-458C70576D59}.Debug|x64.ActiveCfg = Debug|x64 33 | {648A7B22-65ED-4418-8735-458C70576D59}.Debug|x64.Build.0 = Debug|x64 34 | {648A7B22-65ED-4418-8735-458C70576D59}.Release|Win32.ActiveCfg = Debug|Win32 35 | {648A7B22-65ED-4418-8735-458C70576D59}.Release|Win32.Build.0 = Debug|Win32 36 | {648A7B22-65ED-4418-8735-458C70576D59}.Release|x64.ActiveCfg = Debug|x64 37 | {648A7B22-65ED-4418-8735-458C70576D59}.Release|x64.Build.0 = Debug|x64 38 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Debug|Win32.Build.0 = Debug|Win32 40 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Debug|x64.ActiveCfg = Debug|x64 41 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Debug|x64.Build.0 = Debug|x64 42 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Release|Win32.ActiveCfg = Release|Win32 43 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Release|Win32.Build.0 = Release|Win32 44 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Release|x64.ActiveCfg = Release|x64 45 | {5F22CF78-8740-4419-B863-4628DCCFF1D2}.Release|x64.Build.0 = Release|x64 46 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Debug|Win32.ActiveCfg = Debug|x86 47 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Debug|Win32.Build.0 = Debug|x86 48 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Debug|x64.ActiveCfg = Debug|x64 49 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Debug|x64.Build.0 = Debug|x64 50 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Release|Win32.ActiveCfg = Debug|x86 51 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Release|Win32.Build.0 = Debug|x86 52 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Release|x64.ActiveCfg = Debug|x64 53 | {C4B3F342-3734-4DE2-BC4F-2EF80CED3683}.Release|x64.Build.0 = Debug|x64 54 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Debug|Win32.ActiveCfg = Debug|Any CPU 55 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Debug|Win32.Build.0 = Debug|Any CPU 56 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Debug|x64.ActiveCfg = Debug|Any CPU 57 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Debug|x64.Build.0 = Debug|Any CPU 58 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Release|Win32.ActiveCfg = Release|Any CPU 59 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Release|Win32.Build.0 = Release|Any CPU 60 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Release|x64.ActiveCfg = Release|Any CPU 61 | {74DAB335-8C02-4D48-BEF0-BA0A133ACEF7}.Release|x64.Build.0 = Release|Any CPU 62 | EndGlobalSection 63 | GlobalSection(SolutionProperties) = preSolution 64 | HideSolutionNode = FALSE 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /SDbgExt/DumpAspNetRequests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "WinDbgExt.h" 20 | 21 | DBG_FUNC(dumpaspnetrequests) 22 | { 23 | DBG_PREAMBLE; 24 | UNREFERENCED_PARAMETER(args); 25 | UNREFERENCED_PARAMETER(hr); 26 | 27 | auto cb = [&dbg](ClrThreadData threadData)->BOOL { 28 | 29 | CLRDATA_ADDRESS mThread; 30 | ClrThreadContext ctx; ClrHttpContext httpCtx; 31 | if (SUCCEEDED(dbg.Process->GetManagedThreadObject(threadData.ThreadAddress, &mThread)) 32 | && SUCCEEDED(dbg.Process->GetThreadExecutionContext(mThread, &ctx)) 33 | && SUCCEEDED(dbg.Ext->GetHttpContextFromThread(ctx, &httpCtx))) 34 | { 35 | CComBSTR reqUrl, queryString; 36 | reqUrl.Attach(httpCtx.RequestUrl); queryString.Attach(httpCtx.QueryString); 37 | 38 | WCHAR buffer[30] = {0}; 39 | dbg.Process->FormatDateTime(httpCtx.RequestStartTime.Ticks, ARRAYSIZE(buffer), buffer); 40 | dwdprintf(dbg.Control, SR::DumpAspNetRequests_Entry(), 41 | threadData.osThreadId, 42 | ctx.HostContext, 43 | buffer, 44 | reqUrl, 45 | queryString.Length() > 0 ? L"?" : L"", 46 | queryString); 47 | } 48 | 49 | return TRUE; 50 | }; 51 | 52 | dwdprintf(dbg.Control, SR::DumpAspNetRequests_Header()); 53 | 54 | CComObject adapt; 55 | adapt.Init(cb); 56 | dbg.Process->EnumThreads(&adapt); 57 | 58 | return S_OK; 59 | } 60 | 61 | DBG_FUNC(findhttpcontext) 62 | { 63 | DBG_PREAMBLE; 64 | UNREFERENCED_PARAMETER(args); 65 | UNREFERENCED_PARAMETER(hr); 66 | 67 | CComPtr sys; 68 | dbg.Client.QueryInterface(&sys); 69 | 70 | ULONG threadId = 0, dbgThreadId = 0; 71 | sys->GetCurrentThreadSystemId(&threadId); 72 | sys->GetCurrentThreadId(&dbgThreadId); 73 | 74 | dwdprintf(dbg.Control, L"OS ThreadId: %x, N: %d\r\n", threadId, dbgThreadId); 75 | 76 | CLRDATA_ADDRESS umThread = 0, mThread = 0; 77 | if (FAILED(dbg.Process->FindThreadByOsThreadId(threadId, &umThread)) 78 | || FAILED(dbg.Process->GetManagedThreadObject(umThread, &mThread)) 79 | || !mThread) 80 | { 81 | dwdprintf(dbg.Control, L"Unable to find managed thread\r\n"); 82 | return S_OK; 83 | } 84 | 85 | ClrThreadContext ctx = {}; 86 | if (FAILED(dbg.Process->GetThreadExecutionContext(mThread, &ctx))) 87 | { 88 | dwdprintf(dbg.Control, L"Unable to get execution context from managed thread 0x%016p\r\n", mThread); 89 | return S_OK; 90 | } 91 | 92 | dwdprintf(dbg.Control, L"Managed Thread : 0x%016p\r\n", mThread, mThread); 93 | dwdprintf(dbg.Control, L"Thread ExecutionContext : 0x%016p\r\n", ctx.ExecutionContext, ctx.ExecutionContext); 94 | dwdprintf(dbg.Control, L"LogicalCallContext : 0x%016p\r\n", ctx.LogicalCallContext, ctx.LogicalCallContext); 95 | dwdprintf(dbg.Control, L"IllogicalCallContext : 0x%016p\r\n", ctx.IllogicalCallContext, ctx.IllogicalCallContext); 96 | dwdprintf(dbg.Control, L"HostContext (HttpContext) : 0x%016p\r\n", ctx.HostContext, ctx.HostContext); 97 | 98 | ClrHttpContext httpCtx = {}; 99 | if (SUCCEEDED(dbg.Ext->GetHttpContextFromThread(ctx, &httpCtx))) 100 | { 101 | CComBSTR url, qs; 102 | url.Attach(httpCtx.RequestUrl); 103 | qs.Attach(httpCtx.QueryString); 104 | 105 | WCHAR buffer[30] = {0}; 106 | dbg.Process->FormatDateTime(httpCtx.RequestStartTime.Ticks, ARRAYSIZE(buffer), buffer); 107 | 108 | dwdprintf(dbg.Control, L"Request URL : %s%s%s\r\n", httpCtx.RequestUrl, qs.Length() > 0 ? L"?" : L"", qs); 109 | dwdprintf(dbg.Control, L"Request Start Time : %s\r\n", buffer); 110 | } 111 | 112 | return S_OK; 113 | } -------------------------------------------------------------------------------- /SDbgM/SptWrapper/TableWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SPT.Managed 9 | { 10 | public class TableWriter 11 | { 12 | public class HexAddressFormatProvider : IFormatProvider, ICustomFormatter 13 | { 14 | public object GetFormat(Type formatType) 15 | { 16 | if (formatType == typeof(ICustomFormatter)) 17 | { 18 | return this; 19 | } 20 | else 21 | { 22 | return null; 23 | } 24 | } 25 | 26 | public string Format(string format, object arg, IFormatProvider formatProvider) 27 | { 28 | if (arg is ulong && format == "p") 29 | { 30 | if (IntPtr.Size == 4) 31 | { 32 | return ((ulong)arg).ToString("x8"); 33 | } 34 | else 35 | { 36 | return ((ulong)arg).ToString("x16"); 37 | } 38 | 39 | } 40 | else 41 | { 42 | return HandleOtherFormats(format, arg); 43 | } 44 | } 45 | 46 | private string HandleOtherFormats(string format, object arg) 47 | { 48 | if (arg is IFormattable) 49 | return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); 50 | else if (arg != null) 51 | return arg.ToString(); 52 | else 53 | return String.Empty; 54 | } 55 | } 56 | 57 | private readonly SptWrapper _dbg; 58 | private readonly List _columns = new List(); 59 | private int _currCol; 60 | 61 | private struct ColumnInfo 62 | { 63 | public ColumnInfo(int width, bool align) 64 | { 65 | Width = width; 66 | LeftAlign = align; 67 | } 68 | 69 | public readonly int Width; 70 | public readonly bool LeftAlign; 71 | } 72 | 73 | internal TableWriter(SptWrapper wrapper) 74 | { 75 | _currCol = 0; 76 | _dbg = wrapper; 77 | } 78 | 79 | public TableWriter AddColumn(int width, bool leftAlign = false) 80 | { 81 | _columns.Add(new ColumnInfo(width, leftAlign)); 82 | return this; 83 | } 84 | 85 | public TableWriter AddPointerColumn() 86 | { 87 | return AddColumn(IntPtr.Size * 2); 88 | } 89 | 90 | public TableWriter TextColumn(string txt) 91 | { 92 | return Column("{0}", txt); 93 | } 94 | 95 | public TableWriter PointerColumn(ulong ptr) 96 | { 97 | return Column("{0:p}", ptr); 98 | } 99 | 100 | public TableWriter HexColumn(ulong val) 101 | { 102 | return Column("{0:x}", val); 103 | } 104 | 105 | public TableWriter Column(string format, params object[] args) 106 | { 107 | var col = _columns[_currCol++]; 108 | 109 | string ret = string.Format(new HexAddressFormatProvider(), format, args); 110 | 111 | if (col.Width != -1) 112 | { 113 | if (ret.Length > col.Width) 114 | { 115 | ret = "..." + ret.Substring(ret.Length - (col.Width - 3)); 116 | } 117 | else if (ret.Length < col.Width) 118 | { 119 | if (col.LeftAlign) 120 | { 121 | ret = ret.PadRight(col.Width); 122 | } 123 | else 124 | { 125 | ret = ret.PadLeft(col.Width); 126 | } 127 | } 128 | } 129 | 130 | _dbg.DbgOutput(ret + " "); 131 | 132 | return this; 133 | } 134 | 135 | public TableWriter NewRow() 136 | { 137 | _dbg.DbgOutput("\r\n"); 138 | _currCol = 0; 139 | return this; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /SDbgExt/SDbgExt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "SDbgExt.h" 20 | #include "SDbgExtApi.h" 21 | #include "DbgEngCLRDataTarget.h" 22 | #include "DbgEngMemoryAccess.h" 23 | #include 24 | #include 25 | 26 | #define CORDAC_FORMAT L"%s\\Microsoft.NET\\Framework%s\\v%s\\mscordacwks.dll" 27 | 28 | #ifdef _M_IX86 29 | #define CORDAC_BITNESS L"" 30 | #else 31 | #define CORDAC_BITNESS L"64" 32 | #endif 33 | 34 | #ifdef CLR2 35 | #define CORDAC_CLRVER L"2.0.50727" 36 | #else 37 | #define CORDAC_CLRVER L"4.0.30319" 38 | #endif 39 | 40 | HRESULT SDBGEXT_API CreateDbgEngMemoryAccess(IDebugDataSpaces *data, IDacMemoryAccess **ret) 41 | { 42 | CComObject *tmp; 43 | CComObject::CreateInstance(&tmp); 44 | tmp->AddRef(); 45 | tmp->Init(data); 46 | 47 | *ret = tmp; 48 | return S_OK; 49 | } 50 | 51 | HRESULT SDBGEXT_API CreateSDbgExt(IClrProcess *p, ISDbgExt **ext) 52 | { 53 | *ext = CSDbgExt::Construct(p); 54 | return S_OK; 55 | } 56 | 57 | typedef HRESULT (__stdcall *CLRDataCreateInstancePtr)(REFIID iid, ICLRDataTarget* target, void** iface); 58 | 59 | #pragma warning(push) 60 | #pragma warning(disable: 4189) 61 | HRESULT FindCorDac(CComPtr dSym) 62 | { 63 | ULONG corDacIndex = 0; 64 | HRESULT hr = dSym->GetModuleByModuleNameWide(L"clr", 0, &corDacIndex, NULL); 65 | VS_FIXEDFILEINFO fi = {}; 66 | dSym->GetModuleVersionInformationWide(corDacIndex, 0, L"\\", &fi, sizeof(fi), NULL); 67 | 68 | ULONG major = fi.dwProductVersionMS >> 16; 69 | ULONG minor = fi.dwProductVersionMS & 0xFFFF; 70 | ULONG build = fi.dwProductVersionLS >> 16; 71 | ULONG rev = fi.dwFileVersionLS & 0xFFFF; 72 | 73 | return hr; 74 | } 75 | #pragma warning(pop) 76 | 77 | HRESULT SDBGEXT_API InitIXCLRData(IDebugClient *cli, LPCWSTR corDacPathOverride, IXCLRDataProcess3 **ppDac) 78 | { 79 | CComPtr dSym; 80 | CComPtr dds; 81 | CComPtr dso; 82 | 83 | HRESULT hr = S_OK; 84 | 85 | RETURN_IF_FAILED(cli->QueryInterface(__uuidof(IDebugSymbols3), (PVOID*)&dSym)); 86 | RETURN_IF_FAILED(cli->QueryInterface(__uuidof(IDebugDataSpaces), (PVOID*)&dds)); 87 | RETURN_IF_FAILED(cli->QueryInterface(__uuidof(IDebugSystemObjects), (PVOID*)&dso)); 88 | 89 | // Init CORDAC 90 | WCHAR winDirBuffer[MAX_PATH] = { 0 }; 91 | WCHAR corDacBuffer[MAX_PATH] = { 0 }; 92 | 93 | FindCorDac(dSym); 94 | 95 | if (corDacPathOverride == NULL) 96 | { 97 | GetWindowsDirectory(winDirBuffer, ARRAYSIZE(winDirBuffer)); 98 | swprintf_s(corDacBuffer, CORDAC_FORMAT, winDirBuffer, CORDAC_BITNESS, CORDAC_CLRVER); 99 | } 100 | else 101 | { 102 | wcscpy_s(corDacBuffer, corDacPathOverride); 103 | } 104 | 105 | HMODULE hCorDac = LoadLibrary(corDacBuffer); 106 | if (hCorDac == NULL) 107 | { 108 | return FALSE; 109 | } 110 | CLRDataCreateInstancePtr clrData = (CLRDataCreateInstancePtr)GetProcAddress(hCorDac, "CLRDataCreateInstance"); 111 | CComObject *dataTarget; 112 | CComObject::CreateInstance(&dataTarget); 113 | dataTarget->AddRef(); 114 | dataTarget->Init(dSym, dds, dso); 115 | 116 | RETURN_IF_FAILED(clrData(__uuidof(IXCLRDataProcess3), dataTarget, (PVOID*)ppDac)); 117 | 118 | return S_OK; 119 | } 120 | 121 | HRESULT CSDbgExt::GetThreadLimitsFromTEB(IDebugDataSpaces *data, CLRDATA_ADDRESS teb, CLRDATA_ADDRESS *stackBase, CLRDATA_ADDRESS *stackLimit) 122 | { 123 | CComPtr dds(data); 124 | 125 | HRESULT hr = S_OK; 126 | struct TEB_IMP 127 | { 128 | void *junk; 129 | void *stackBase; 130 | void *stackLimit; 131 | }; 132 | 133 | TEB_IMP threadTeb = {}; 134 | RETURN_IF_FAILED(dds->ReadVirtual(teb, (PVOID)&threadTeb, sizeof(TEB_IMP), NULL)); 135 | 136 | *stackBase = (CLRDATA_ADDRESS)(threadTeb.stackBase); 137 | *stackLimit = (CLRDATA_ADDRESS)(threadTeb.stackLimit); 138 | 139 | return S_OK; 140 | } -------------------------------------------------------------------------------- /SDbgExt/CSDbgBootstrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SDbgExt2 - Copyright (C) 2013, Steve Niemitz 3 | 4 | SDbgExt2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | SDbgExt2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with SDbgExt2. If not, see . 16 | */ 17 | 18 | #include "stdafx.h" 19 | #include "CSDbgBootstrapper.h" 20 | #include 21 | 22 | HRESULT SDBGEXT_API CreateBootstrapper(ISDbgBootstrapper **ret) 23 | { 24 | CComObject *bootstrapper; 25 | CComObject::CreateInstance(&bootstrapper); 26 | bootstrapper->AddRef(); 27 | 28 | *ret = bootstrapper; 29 | return S_OK; 30 | } 31 | 32 | HRESULT SDBGEXT_API CreateBootsrapperFromWinDBG(IDebugClient *cli, ISDbgBootstrapper **ret) 33 | { 34 | CComObject *bootstrapper; 35 | CComObject::CreateInstance(&bootstrapper); 36 | bootstrapper->AddRef(); 37 | bootstrapper->setClient(cli); 38 | bootstrapper->setIsDump(TRUE); 39 | 40 | *ret = bootstrapper; 41 | return S_OK; 42 | } 43 | 44 | HRESULT CSDbgBootstrapper::InitIXCLRDataFromWinDBG(WINDBG_EXTENSION_APIS64 *apis, IXCLRDataProcess3 **ppDac) 45 | { 46 | WDBGEXTS_CLR_DATA_INTERFACE ixDataQuery; 47 | 48 | ixDataQuery.Iid = &__uuidof(IXCLRDataProcess3); 49 | ULONG ret = (apis->lpIoctlRoutine)(IG_GET_CLR_DATA_INTERFACE, &ixDataQuery, sizeof(ixDataQuery)); 50 | if (!ret) 51 | { 52 | return E_FAIL; 53 | } 54 | 55 | *ppDac = (IXCLRDataProcess3*)ixDataQuery.Iface; 56 | 57 | return S_OK; 58 | } 59 | 60 | HRESULT CSDbgBootstrapper::EnsureDbgClient() 61 | { 62 | HRESULT hr = S_OK; 63 | if (m_cli == nullptr) 64 | { 65 | RETURN_IF_FAILED(DebugCreate(__uuidof(IDebugClient), (PVOID*)&(m_cli))); 66 | } 67 | CComPtr sym; 68 | m_cli.QueryInterface(&sym); 69 | 70 | if (m_imgPath.size() > 0) 71 | { 72 | sym->SetImagePathWide(m_imgPath.c_str()); 73 | } 74 | if (m_symPath.size() > 0) 75 | { 76 | sym->SetSymbolPathWide(m_symPath.c_str()); 77 | } 78 | if (m_symOptions) 79 | { 80 | sym->AddSymbolOptions(m_symOptions); 81 | } 82 | return hr; 83 | } 84 | 85 | STDMETHODIMP CSDbgBootstrapper::InitFromLiveProcess(DWORD dwProcessId, ISDbgExt **ret) 86 | { 87 | CComPtr cli; 88 | CComPtr ctrl; 89 | 90 | HRESULT hr = S_OK; 91 | RETURN_IF_FAILED(EnsureDbgClient()); 92 | RETURN_IF_FAILED(m_cli.QueryInterface(&ctrl)); 93 | 94 | RETURN_IF_FAILED(m_cli->AttachProcess(NULL, dwProcessId, DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND)); 95 | RETURN_IF_FAILED(ctrl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)); 96 | 97 | m_isDumpFile = FALSE; 98 | return Init(ret); 99 | } 100 | 101 | HRESULT InitIXCLRDataFromWinDBG(WINDBG_EXTENSION_APIS64 *apis, IXCLRDataProcess3 **ppDac); 102 | 103 | STDMETHODIMP CSDbgBootstrapper::InitFromDump(LPWSTR dumpFile, ISDbgExt **ext) 104 | { 105 | CComPtr cli4; 106 | CComPtr ctrl; 107 | 108 | HRESULT hr = S_OK; 109 | RETURN_IF_FAILED(EnsureDbgClient()); 110 | RETURN_IF_FAILED(m_cli.QueryInterface(&cli4)); 111 | RETURN_IF_FAILED(m_cli.QueryInterface(&ctrl)); 112 | 113 | RETURN_IF_FAILED(cli4->OpenDumpFileWide(dumpFile, NULL)); 114 | RETURN_IF_FAILED(ctrl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)); 115 | 116 | m_isDumpFile = TRUE; 117 | return Init(ext); 118 | } 119 | 120 | STDMETHODIMP CSDbgBootstrapper::Init(ISDbgExt **ext) 121 | { 122 | HRESULT hr = S_OK; 123 | CComPtr ctrl; 124 | CComPtr cli4; 125 | CComPtr dds; 126 | 127 | CComPtr dac; 128 | CComPtr dcma; 129 | CComPtr p; 130 | 131 | RETURN_IF_FAILED(EnsureDbgClient()); 132 | 133 | m_cli.QueryInterface(&ctrl); 134 | m_cli.QueryInterface(&dds); 135 | 136 | if (m_isDumpFile) 137 | { 138 | WINDBG_EXTENSION_APIS64 extApis; 139 | extApis.nSize = sizeof(WINDBG_EXTENSION_APIS64); 140 | ctrl->GetWindbgExtensionApis64(&extApis); 141 | RETURN_IF_FAILED(InitIXCLRDataFromWinDBG((WINDBG_EXTENSION_APIS64 *)&extApis, &dac)); 142 | } 143 | else 144 | { 145 | RETURN_IF_FAILED(InitIXCLRData(m_cli, NULL, &dac)); 146 | } 147 | 148 | CreateDbgEngMemoryAccess(dds, &dcma); 149 | CreateClrProcess(dac, dcma, &p); 150 | CreateSDbgExt(p, ext); 151 | 152 | return hr; 153 | } --------------------------------------------------------------------------------