From df1c3afb65e52386ffd6d469793845a0f06b176e Mon Sep 17 00:00:00 2001
From: "SND\\EreTIk_cp" <SND\EreTIk_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Thu, 29 Dec 2011 19:56:00 +0000
Subject: [PATCH] [0.1.x] +sub-registers in thread context

git-svn-id: https://pykd.svn.codeplex.com/svn@72770 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd/context.cpp           | 159 +++++++++++++++++++++++++++++++++++++
 pykd/context.h             |  16 ++++
 pykd/dbgext.cpp            |   2 +
 pykd/process.cpp           |   2 +-
 test/scripts/clienttest.py |  14 +++-
 5 files changed, 190 insertions(+), 3 deletions(-)

diff --git a/pykd/context.cpp b/pykd/context.cpp
index 120ca46..08a77d1 100644
--- a/pykd/context.cpp
+++ b/pykd/context.cpp
@@ -145,6 +145,14 @@ Registers::Registers(
 
 ULONG64 Registers::getValue(ULONG cvRegId) const
 {
+    try
+    {
+        return getSubValue(cvRegId);
+    }
+    catch (const IsNotSubRegister &)
+    {
+    }
+
     RegValues::const_iterator it = m_regValues.find(cvRegId);
     if (it == m_regValues.end())
         throw Exception(__FUNCTION__ ": Register missing");
@@ -155,6 +163,19 @@ ULONG64 Registers::getValue(ULONG cvRegId) const
 
 bool Registers::getValueNoThrow(ULONG cvRegId, ULONG64 &val) const
 {
+    try
+    {
+        val = getSubValue(cvRegId);
+        return true;
+    }
+    catch (const IsNotSubRegister &)
+    {
+    }
+    catch (const Exception &)
+    {
+        return false;
+    }
+
     RegValues::const_iterator it = m_regValues.find(cvRegId);
     if (it == m_regValues.end())
         return false;
@@ -209,6 +230,144 @@ python::object Registers::getByIndex(ULONG ind) const
 
 /////////////////////////////////////////////////////////////////////////////////
 
+struct SubRegister {
+    ULONG m_fromReg;
+    ULONG m_bitsShift;
+    ULONG m_bitsMask;
+
+    void set(ULONG fromReg, ULONG bitsShift, ULONG bitsMask)
+    {
+        m_fromReg = fromReg; m_bitsShift = bitsShift; m_bitsMask = bitsMask; 
+    }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+static const class SubRegisterMapI386 : public std::map<ULONG, SubRegister> {
+public:
+    SubRegisterMapI386();
+} g_SubRegistersI386;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+SubRegisterMapI386::SubRegisterMapI386()
+{
+    (*this)[CV_REG_AL].set(CV_REG_EAX, 0x00, 0xff);
+    (*this)[CV_REG_CL].set(CV_REG_ECX, 0x00, 0xff);
+    (*this)[CV_REG_DL].set(CV_REG_EDX, 0x00, 0xff);
+    (*this)[CV_REG_BL].set(CV_REG_EBX, 0x00, 0xff);
+
+    (*this)[CV_REG_AH].set(CV_REG_EAX, 0x08, 0xff);
+    (*this)[CV_REG_CH].set(CV_REG_ECX, 0x08, 0xff);
+    (*this)[CV_REG_DH].set(CV_REG_EDX, 0x08, 0xff);
+    (*this)[CV_REG_BH].set(CV_REG_EBX, 0x08, 0xff);
+
+    (*this)[CV_REG_AX].set(CV_REG_EAX, 0x00, 0xffff);
+    (*this)[CV_REG_CX].set(CV_REG_ECX, 0x00, 0xffff);
+    (*this)[CV_REG_DX].set(CV_REG_EDX, 0x00, 0xffff);
+    (*this)[CV_REG_BX].set(CV_REG_EBX, 0x00, 0xffff);
+
+    (*this)[CV_REG_SP].set(CV_REG_ESP, 0x00, 0xffff);
+    (*this)[CV_REG_BP].set(CV_REG_EBP, 0x00, 0xffff);
+    (*this)[CV_REG_SI].set(CV_REG_ESI, 0x00, 0xffff);
+    (*this)[CV_REG_DI].set(CV_REG_EDI, 0x00, 0xffff);
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+static const class SubRegisterMapAmd64 : public std::map<ULONG, SubRegister> {
+public:
+    SubRegisterMapAmd64();
+} g_SubRegistersAmd64;
+
+/////////////////////////////////////////////////////////////////////////////////
+
+SubRegisterMapAmd64::SubRegisterMapAmd64()
+{
+    (*this)[CV_AMD64_AL].set(CV_AMD64_RAX, 0x00, 0xff);
+    (*this)[CV_AMD64_CL].set(CV_AMD64_RCX, 0x00, 0xff);
+    (*this)[CV_AMD64_DL].set(CV_AMD64_RDX, 0x00, 0xff);
+    (*this)[CV_AMD64_BL].set(CV_AMD64_RBX, 0x00, 0xff);
+
+    (*this)[CV_AMD64_AH].set(CV_AMD64_RAX, 0x08, 0xff);
+    (*this)[CV_AMD64_CH].set(CV_AMD64_RCX, 0x08, 0xff);
+    (*this)[CV_AMD64_DH].set(CV_AMD64_RDX, 0x08, 0xff);
+    (*this)[CV_AMD64_BH].set(CV_AMD64_RBX, 0x08, 0xff);
+
+    (*this)[CV_AMD64_AX].set(CV_AMD64_RAX, 0x00, 0xffff);
+    (*this)[CV_AMD64_CX].set(CV_AMD64_RCX, 0x00, 0xffff);
+    (*this)[CV_AMD64_DX].set(CV_AMD64_RDX, 0x00, 0xffff);
+    (*this)[CV_AMD64_BX].set(CV_AMD64_RBX, 0x00, 0xffff);
+
+    (*this)[CV_AMD64_SP].set(CV_AMD64_RSP, 0x00, 0xffff);
+    (*this)[CV_AMD64_BP].set(CV_AMD64_RBP, 0x00, 0xffff);
+    (*this)[CV_AMD64_SI].set(CV_AMD64_RSI, 0x00, 0xffff);
+    (*this)[CV_AMD64_DI].set(CV_AMD64_RDI, 0x00, 0xffff);
+
+    (*this)[CV_AMD64_EAX].set(CV_AMD64_RAX, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_ECX].set(CV_AMD64_RCX, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_EDX].set(CV_AMD64_RDX, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_EBX].set(CV_AMD64_RBX, 0x00, 0xffffffff);
+
+    (*this)[CV_AMD64_ESP].set(CV_AMD64_RSP, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_EBP].set(CV_AMD64_RBP, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_ESI].set(CV_AMD64_RSI, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_EDI].set(CV_AMD64_RDI, 0x00, 0xffffffff);
+
+    (*this)[CV_AMD64_R8B].set(CV_AMD64_R8, 0x00, 0xff);
+    (*this)[CV_AMD64_R9B].set(CV_AMD64_R9, 0x00, 0xff);
+    (*this)[CV_AMD64_R10B].set(CV_AMD64_R10, 0x00, 0xff);
+    (*this)[CV_AMD64_R11B].set(CV_AMD64_R11, 0x00, 0xff);
+    (*this)[CV_AMD64_R12B].set(CV_AMD64_R12, 0x00, 0xff);
+    (*this)[CV_AMD64_R13B].set(CV_AMD64_R13, 0x00, 0xff);
+    (*this)[CV_AMD64_R14B].set(CV_AMD64_R14, 0x00, 0xff);
+    (*this)[CV_AMD64_R15B].set(CV_AMD64_R15, 0x00, 0xff);
+
+    (*this)[CV_AMD64_R8W].set(CV_AMD64_R8, 0x00, 0xffff);
+    (*this)[CV_AMD64_R9W].set(CV_AMD64_R9, 0x00, 0xffff);
+    (*this)[CV_AMD64_R10W].set(CV_AMD64_R10, 0x00, 0xffff);
+    (*this)[CV_AMD64_R11W].set(CV_AMD64_R11, 0x00, 0xffff);
+    (*this)[CV_AMD64_R12W].set(CV_AMD64_R12, 0x00, 0xffff);
+    (*this)[CV_AMD64_R13W].set(CV_AMD64_R13, 0x00, 0xffff);
+    (*this)[CV_AMD64_R14W].set(CV_AMD64_R14, 0x00, 0xffff);
+    (*this)[CV_AMD64_R15W].set(CV_AMD64_R15, 0x00, 0xffff);
+
+    (*this)[CV_AMD64_R8D].set(CV_AMD64_R8, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R9D].set(CV_AMD64_R9, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R10D].set(CV_AMD64_R10, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R11D].set(CV_AMD64_R11, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R12D].set(CV_AMD64_R12, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R13D].set(CV_AMD64_R13, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R14D].set(CV_AMD64_R14, 0x00, 0xffffffff);
+    (*this)[CV_AMD64_R15D].set(CV_AMD64_R15, 0x00, 0xffffffff);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+ULONG64 Registers::getSubValue(ULONG cvRegId) const
+{
+    const std::map<ULONG, SubRegister> *subRegs = NULL;
+    if (IMAGE_FILE_MACHINE_I386 == m_processorType)
+        subRegs = &g_SubRegistersI386;
+    else 
+        subRegs = &g_SubRegistersAmd64;
+
+    std::map<ULONG, SubRegister>::const_iterator itSubReg = 
+        subRegs->find(cvRegId);
+    if (itSubReg == subRegs->end())
+        throw IsNotSubRegister();
+
+    RegValues::const_iterator itFullReg = m_regValues.find(itSubReg->second.m_fromReg);
+    if (itFullReg == m_regValues.end())
+        throw Exception(__FUNCTION__ ": Register missing");
+
+    return 
+        (itFullReg->second >> itSubReg->second.m_bitsShift) & itSubReg->second.m_bitsMask;
+}
+
+// ----------------------------------------------------------------------------
+
 }
 
 /////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/context.h b/pykd/context.h
index f9f9269..7753fd2 100644
--- a/pykd/context.h
+++ b/pykd/context.h
@@ -7,6 +7,10 @@
 
 #pragma once
 
+namespace pykd{
+    std::string processorToStr(ULONG processorMode);
+}
+
 namespace Ctx {
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -42,8 +46,17 @@ public:
     }
     python::object getByIndex(ULONG ind) const;
 
+    // get processor type
+    std::string getProcessorType() const {
+        return pykd::processorToStr(m_processorType);
+    }
+
 private:
 
+    struct IsNotSubRegister : public std::exception {
+        IsNotSubRegister() : std::exception("is not sub-register") { }
+    };
+
     // query i386 registers
     void getI386Context(
         IDebugAdvanced2 *advanced
@@ -54,6 +67,9 @@ private:
         IDebugAdvanced2 *advanced
     );
 
+    // try query as "sub-register"
+    ULONG64 getSubValue(ULONG cvRegId) const;
+
 private:
     typedef std::map<ULONG, ULONG64> RegValues;
     RegValues m_regValues;
diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp
index 95f1505..22b8aaf 100644
--- a/pykd/dbgext.cpp
+++ b/pykd/dbgext.cpp
@@ -604,6 +604,8 @@ BOOST_PYTHON_MODULE( pykd )
             "Get current stack pointer" )
         .def( "get", &Ctx::Registers::getValue, 
             "Get register value by ID (CV_REG_XXX)" )
+        .def( "processorType", &Ctx::Registers::getProcessorType,
+            "Get processor type as string")
         .def("__len__", &Ctx::Registers::getCount,
             "Return count of registers")
         .def("__getitem__", &Ctx::Registers::getByIndex,
diff --git a/pykd/process.cpp b/pykd/process.cpp
index 1f58d5e..ac6a817 100644
--- a/pykd/process.cpp
+++ b/pykd/process.cpp
@@ -78,7 +78,7 @@ getCurrentStack()
 
 ///////////////////////////////////////////////////////////////////////////////////
 
-static std::string processorToStr(ULONG processorMode)
+std::string processorToStr(ULONG processorMode)
 {
     switch( processorMode )
     {
diff --git a/test/scripts/clienttest.py b/test/scripts/clienttest.py
index a004fc9..29cfdee 100644
--- a/test/scripts/clienttest.py
+++ b/test/scripts/clienttest.py
@@ -26,15 +26,25 @@ class DbgClientTest( unittest.TestCase ):
         ctx = pykd.getContext()
 #        for reg in ctx:
 #            regName = ""
-#            try:
+#            if ctx.processorType() == "X86":
 #                regName = pykd.diaI386Regs[ reg[0] ]
-#            except KeyError:
+#            else:
 #                regName = pykd.diaAmd64Regs[ reg[0] ]
 #            pykd.dprint( "\n" + regName + ": 0x%x " % reg[1])
         self.assertNotEqual( 0, len(ctx) )
         self.assertNotEqual( 0, ctx.ip() )
         self.assertNotEqual( 0, ctx.csp() )
 
+        self.assertEqual( (ctx.get(pykd.CV_REG_AH) << 8) | ctx.get(pykd.CV_REG_AL), ctx.get(pykd.CV_REG_AX) )
+        self.assertEqual( ctx.get(pykd.CV_REG_AX), ctx.get(pykd.CV_REG_EAX) & 0xffff )
+        if ctx.processorType() == "X64":
+            self.assertEqual( ctx.get(pykd.CV_REG_EAX), ctx.get(pykd.CV_AMD64_RAX) & 0xffffffff )
+
+        self.assertEqual( (ctx.get(pykd.CV_REG_DH) << 8) | ctx.get(pykd.CV_REG_DL), ctx.get(pykd.CV_REG_DX) )
+        self.assertEqual( ctx.get(pykd.CV_REG_DX), ctx.get(pykd.CV_REG_EDX) & 0xffff )
+        if ctx.processorType() == "X64":
+            self.assertEqual( ctx.get(pykd.CV_REG_EDX), ctx.get(pykd.CV_AMD64_RDX) & 0xffffffff )
+
     def testIsDumpAnalyzing( self ):
         self.assertFalse( pykd.isDumpAnalyzing() )