diff --git a/pykd/pykd_vc120.vcxproj b/pykd/pykd_vc120.vcxproj index 92ddd55..e656bf6 100644 --- a/pykd/pykd_vc120.vcxproj +++ b/pykd/pykd_vc120.vcxproj @@ -590,6 +590,7 @@ <ClInclude Include="pymodule.h" /> <ClInclude Include="pyprocess.h" /> <ClInclude Include="pysymengine.h" /> + <ClInclude Include="pytagged.h" /> <ClInclude Include="pythreadstate.h" /> <ClInclude Include="pytypedvar.h" /> <ClInclude Include="pytypeinfo.h" /> @@ -623,6 +624,7 @@ </ClCompile> <ClCompile Include="pymodule.cpp" /> <ClCompile Include="pyprocess.cpp" /> + <ClCompile Include="pytagged.cpp" /> <ClCompile Include="pytypedvar.cpp" /> <ClCompile Include="pytypeinfo.cpp" /> <ClCompile Include="stdafx.cpp"> diff --git a/pykd/pykd_vc120.vcxproj.filters b/pykd/pykd_vc120.vcxproj.filters index 464d7d1..3f4b9b1 100644 --- a/pykd/pykd_vc120.vcxproj.filters +++ b/pykd/pykd_vc120.vcxproj.filters @@ -81,6 +81,9 @@ <ClInclude Include="pydataaccess.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="pytagged.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="stdafx.cpp"> @@ -248,6 +251,9 @@ <ClCompile Include="pyprocess.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="pytagged.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="pykd.def"> diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index a2218c4..624168a 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -20,6 +20,7 @@ #include "pytypeinfo.h" #include "pycpucontext.h" #include "pyprocess.h" +#include "pytagged.h" using namespace pykd; @@ -597,6 +598,12 @@ BOOST_PYTHON_MODULE( pykd ) python::def( "removeSyntheticSymbol", pykd::removeSyntheticSymbol, "The removeSyntheticSymbol function removes a synthetic symbol from a module in the current proces" ); + // secondary callback data + python::def("enumTagged", pykd::enumTagged, + "Return the list of secondary callback data IDs (as a strings)" ); + python::def("loadTaggedBuffer", pykd::loadTaggedBuffer, + "Read the buffer of secondary callback data by ID" ); + python::class_<kdlib::NumBehavior, boost::noncopyable>( "numVariant", "numVariant", python::no_init ) .def("__init__", python::make_constructor(&NumVariantAdaptor::getVariant) ) .def( "__eq__", &NumVariantAdaptor::eq ) diff --git a/pykd/pytagged.cpp b/pykd/pytagged.cpp new file mode 100644 index 0000000..a20b8d5 --- /dev/null +++ b/pykd/pytagged.cpp @@ -0,0 +1,76 @@ + +#include "stdafx.h" + +#include "pytagged.h" +#include "kdlib\tagged.h" +#include "kdlib\exceptions.h" + +#include "pythreadstate.h" +#include "stladaptor.h" + +#include <rpc.h> +#pragma comment(lib, "Rpcrt4.lib") + + +namespace pykd { + + +void __declspec(noreturn) throwRpcStatus( const std::string &functionName, RPC_STATUS status ) +{ + std::stringstream sstr; + sstr << "Call " << functionName << " failed\n"; + sstr << "RPC_STATUS 0x" << std::hex << status; + throw kdlib::DbgException( sstr.str() ); +} + +python::list enumTagged() +{ + std::list<kdlib::TaggedId> ids; + { + AutoRestorePyState pystate; + ids = std::move( kdlib::enumTagged() ); + } + + python::list result; + + for (const auto &id : ids) + { + RPC_WSTR id_str = nullptr; + auto status = ::UuidToString(&id, &id_str); + if (RPC_S_OK != status) + throwRpcStatus("UuidToString", status); + + const auto stringFree = + [](RPC_WSTR *str) + { + auto status = ::RpcStringFree(str); + if (RPC_S_OK != status) + throwRpcStatus("RpcStringFree", status); + }; + std::unique_ptr<RPC_WSTR, decltype(stringFree)> freeGuard{&id_str, stringFree}; + + result.append( std::wstring(reinterpret_cast<wchar_t *>(id_str)) ); + } + return result; +} + +python::list loadTaggedBuffer(const std::wstring &id_str) +{ + const auto rcp_str = + reinterpret_cast<RPC_WSTR>( const_cast<wchar_t *>(id_str.c_str()) ); + kdlib::TaggedId id; + auto status = ::UuidFromString(rcp_str, &id); + if (RPC_S_OK != status) + throwRpcStatus("UuidFromString", status); + + + kdlib::TaggedBuffer buff; + { + AutoRestorePyState pystate; + buff = std::move( kdlib::loadTaggedBuffer(id) ); + } + + return vectorToList(buff); +} + +} // namespace pykd diff --git a/pykd/pytagged.h b/pykd/pytagged.h new file mode 100644 index 0000000..d688e51 --- /dev/null +++ b/pykd/pytagged.h @@ -0,0 +1,12 @@ + +#pragma once + +namespace python = boost::python; + +namespace pykd { + +python::list enumTagged(); + +python::list loadTaggedBuffer(const std::wstring &id_str); + +} // namespace pykd diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 810f0ee..df433b9 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -27,6 +27,7 @@ import excepttest import targetprocess import ehloadtest import synsymtest +import taggedtest pykd.initialize() @@ -65,6 +66,7 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( mspdbtest.MsPdbTest ), unittest.TestLoader().loadTestsFromTestCase( targetprocess.ProcessTest ), unittest.TestLoader().loadTestsFromTestCase( ehloadtest.EhLoadTest ), + unittest.TestLoader().loadTestsFromTestCase( taggedtest.TaggedTest ), #unittest.TestLoader().loadTestsFromTestCase( excepttest.ExceptionTest ), ] ) diff --git a/test/scripts/pykdtest.pyproj b/test/scripts/pykdtest.pyproj index 0708c66..61f3761 100644 --- a/test/scripts/pykdtest.pyproj +++ b/test/scripts/pykdtest.pyproj @@ -50,6 +50,7 @@ <Compile Include="regtest.py" /> <Compile Include="stacktest.py" /> <Compile Include="synsymtest.py" /> + <Compile Include="taggedtest.py" /> <Compile Include="target.py" /> <Compile Include="targetprocess.py" /> <Compile Include="testutils.py" /> diff --git a/test/scripts/taggedtest.py b/test/scripts/taggedtest.py new file mode 100644 index 0000000..49d7a4a --- /dev/null +++ b/test/scripts/taggedtest.py @@ -0,0 +1,31 @@ +import unittest +import pykd +import sys +import os + +class TaggedTest(unittest.TestCase): + def setUp(self): + dump_file = os.path.join( os.path.dirname(sys.argv[0]), + r"..\..\kdlibcpp\kdlib\tests\dumps\win8_x64_mem.cab" ) + self.dump_id = pykd.loadDump( dump_file ) + + self._existing_id = "D03DC06F-D88E-44C5-BA2A-FAE035172D19" + self._non_existing_id = "88597A32-1493-41CA-BF87-2A950DF4CEE0" + + def tearDown(self): + pykd.closeDump( self.dump_id ) + + def testEnum(self): + ids = pykd.enumTagged() + + self.assertTrue( self._existing_id.lower() in [i.lower() for i in ids] ) + + self.assertFalse( self._non_existing_id.lower() in [i.lower() for i in ids] ) + + + def testLoadBuffer(self): + buff = pykd.loadTaggedBuffer( self._existing_id ) + self.assertEqual( len(buff), 0x410 ) + + self.assertRaises( pykd.DbgException, pykd.loadTaggedBuffer, self._non_existing_id ) +