From bc3259e9160563a1a5cc7ec5f4a8ce06ded7df8a Mon Sep 17 00:00:00 2001
From: "SND\\EreTIk_cp" <SND\EreTIk_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Wed, 30 Nov 2011 18:40:57 +0000
Subject: [PATCH] [0.1.x] add: synthetic symbols implementation

git-svn-id: https://pykd.svn.codeplex.com/svn@71929 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd/dbgclient.cpp              |  11 +-
 pykd/dbgclient.h                |  74 +++++++++-
 pykd/dbgext.cpp                 |  30 +++-
 pykd/dbgobj.h                   |   7 +-
 pykd/inteventhandler.cpp        |  76 ++++++++++
 pykd/inteventhandler.h          |  45 ++++++
 pykd/module.cpp                 |  25 +++-
 pykd/module.h                   |  20 +--
 pykd/pykd_2008.vcproj           |  26 +++-
 pykd/synsymbol.cpp              | 248 ++++++++++++++++++++++++++++++++
 pykd/synsymbol.h                | 144 +++++++++++++++++++
 pykd/synsymhelpers.cpp          | 152 ++++++++++++++++++++
 pykd/synsymhelpers.h            | 107 ++++++++++++++
 test/scripts/pykdtest.py        |   6 +-
 test/scripts/synsymtest.py      |  68 +++++++++
 test/targetapp/targetapp.vcproj |   6 +-
 16 files changed, 1018 insertions(+), 27 deletions(-)
 create mode 100644 pykd/inteventhandler.cpp
 create mode 100644 pykd/inteventhandler.h
 create mode 100644 pykd/synsymbol.cpp
 create mode 100644 pykd/synsymbol.h
 create mode 100644 pykd/synsymhelpers.cpp
 create mode 100644 pykd/synsymhelpers.h
 create mode 100644 test/scripts/synsymtest.py

diff --git a/pykd/dbgclient.cpp b/pykd/dbgclient.cpp
index 20c6294..ba96444 100644
--- a/pykd/dbgclient.cpp
+++ b/pykd/dbgclient.cpp
@@ -12,6 +12,15 @@ DebugClientPtr  g_dbgClient( DebugClient::createDbgClient() );
 
 ///////////////////////////////////////////////////////////////////////////////////
 
+DebugClient::DebugClient( IDebugClient4 *client )
+    : DbgObject( client )
+    , m_symSymbols( new SyntheticSymbols(*m_symbols, *this) )
+    , m_internalDbgEventHandler(client, m_symSymbols)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
 DebugClientPtr DebugClient::createDbgClient() {
 
     HRESULT                  hres;
@@ -315,4 +324,4 @@ ULONG ptrSize()
 
 ///////////////////////////////////////////////////////////////////////////////////
 
-}; // end of namespace pykd
\ No newline at end of file
+}; // end of namespace pykd
diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h
index a2aeb9c..cb6db3a 100644
--- a/pykd/dbgclient.h
+++ b/pykd/dbgclient.h
@@ -14,6 +14,8 @@
 #include "pyaux.h"
 #include "disasm.h"
 #include "cpureg.h"
+#include "inteventhandler.h"
+#include "synsymbol.h"
 
 /////////////////////////////////////////////////////////////////////////////////
 
@@ -97,11 +99,11 @@ public:
     void loadDump( const std::wstring &fileName );
 
     Module loadModuleByName( const std::string  &moduleName ) {
-        return Module( m_client, moduleName );
+        return Module( m_client, m_symSymbols, moduleName );
     }
 
     Module loadModuleByOffset( ULONG64  offset ) {
-        return Module( m_client, offset ); 
+        return Module( m_client, m_symSymbols, offset ); 
     }
 
     DbgExtensionPtr loadExtension( const std::wstring &extPath ) {
@@ -191,6 +193,35 @@ public:
         return m_pyThreadState;
     }
 
+    void addSyntheticSymbol(
+        ULONG64 addr,
+        ULONG size,
+        const std::string &symName
+    )
+    {
+        return m_symSymbols->add(addr, size, symName);
+    }
+
+    void delAllSyntheticSymbols()
+    {
+        return m_symSymbols->clear();
+    }
+
+    ULONG delSyntheticSymbol(
+        ULONG64 addr
+    )
+    {
+        return m_symSymbols->remove(addr);
+    }
+
+    ULONG delSyntheticSymbolsMask(
+        const std::string &moduleName,
+        const std::string &symName
+    )
+    {
+        return m_symSymbols->removeByMask(moduleName, symName);
+    }
+
 private:
 
     template<typename T>
@@ -200,7 +231,10 @@ private:
     //python::list
     //loadArray( ULONG64 offset, ULONG count, bool phyAddr );
 
-    DebugClient( IDebugClient4 *client ) : DbgObject( client ) {}
+    SynSymbolsPtr m_symSymbols; // DebugClient is creator
+    InternalDbgEventHandler m_internalDbgEventHandler;
+
+    DebugClient( IDebugClient4 *client );
 
     PyThreadStateSaver      m_pyThreadState;
 };
@@ -235,6 +269,38 @@ void setExecutionStatus( ULONG status );
 
 void waitForEvent();
 
+/////////////////////////////////////////////////////////////////////////////////
+// Synthetic symbols global finctions:
+
+inline void addSyntheticSymbol(
+    ULONG64 addr,
+    ULONG size,
+    const std::string &symName
+)
+{
+    return g_dbgClient->addSyntheticSymbol(addr, size, symName);
+}
+
+inline void delAllSyntheticSymbols()
+{
+    return g_dbgClient->delAllSyntheticSymbols();
+}
+
+inline ULONG delSyntheticSymbol(
+    ULONG64 addr
+)
+{
+    return g_dbgClient->delSyntheticSymbol(addr);
+}
+
+inline ULONG delSyntheticSymbolsMask(
+    const std::string &moduleName,
+    const std::string &symName
+)
+{
+    return g_dbgClient->delSyntheticSymbolsMask(moduleName, symName);
+}
+
 /////////////////////////////////////////////////////////////////////////////////
 
 template<ULONG status>
@@ -331,4 +397,4 @@ void changeDebuggerStatus()
 //
 //extern dbgClient    g_dbgClient;
 //
-/////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
+/////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp
index 2f97a68..9c8851a 100644
--- a/pykd/dbgext.cpp
+++ b/pykd/dbgext.cpp
@@ -234,7 +234,15 @@ BOOST_PYTHON_MODULE( pykd )
         .def( "trace", &pykd::DebugClient::changeDebuggerStatus<DEBUG_STATUS_STEP_INTO>, 
             "Change debugger status to DEBUG_STATUS_STEP_INTO" )
         .def( "waitForEvent", &pykd::DebugClient::waitForEvent,
-            "Wait for events that breaks into the debugger" );
+            "Wait for events that breaks into the debugger" )
+        .def( "addSynSymbol", &pykd::DebugClient::addSyntheticSymbol,
+            "Add new synthetic symbol for virtual address" )
+        .def( "delAllSynSymbols", &pykd::DebugClient::delAllSyntheticSymbols, 
+            "Delete all synthetic symbol for all modules")
+        .def( "delSynSymbol", &pykd::DebugClient::delSyntheticSymbol, 
+            "Delete synthetic symbols by virtual address" )
+        .def( "delSynSymbolsMask", &pykd::DebugClient::delSyntheticSymbolsMask, 
+            "Delete synthetic symbols by mask of module and symbol name");
 
     python::def( "addr64", &addr64,
         "Extend address to 64 bits formats" );
@@ -318,6 +326,16 @@ BOOST_PYTHON_MODULE( pykd )
         "Read an signed mashine's word wide integer from the target memory" );
     python::def( "ptrPtr", &ptrPtr,
         "Read an pointer value from the target memory" );
+
+    boost::python::def( "addSynSymbol", &addSyntheticSymbol,
+        "Add new synthetic symbol for virtual address" );
+    boost::python::def( "delAllSynSymbols", &delAllSyntheticSymbols, 
+        "Delete all synthetic symbol for all modules");
+    boost::python::def( "delSynSymbol", &delSyntheticSymbol, 
+        "Delete synthetic symbols by virtual address" );
+    boost::python::def( "delSynSymbolsMask", &delSyntheticSymbolsMask, 
+        "Delete synthetic symbols by mask of module and symbol name");
+
     python::def( "loadExt", &pykd::loadExtension,
         "Load a debuger extension" );
     python::def( "loadModule", &loadModuleByName,
@@ -610,6 +628,8 @@ BOOST_PYTHON_MODULE( pykd )
     // wrapper for standart python exceptions
     python::register_exception_translator<pykd::PyException>( &PyException::exceptionTranslate );
 
+#define _DECL_BASE_EXCEPT_STR   .def( "__str__", &pykd::DbgException::print )
+
     // base exception
     python::class_<pykd::DbgException>  dbgExceptionClass( "BaseException",
         "Pykd base exception class",
@@ -618,17 +638,17 @@ BOOST_PYTHON_MODULE( pykd )
         .def( python::init<std::string>( python::args("desc"), "constructor" ) )
         .def( "desc", &pykd::DbgException::getDesc,
             "Get exception description" )
-        .def( "__str__", &pykd::DbgException::print);
+        _DECL_BASE_EXCEPT_STR;
     pykd::DbgException::setTypeObject( dbgExceptionClass.ptr() );
     python::register_exception_translator<pykd::DbgException>( 
         &pykd::DbgException::exceptionTranslate );
 
     // DIA exceptions
     python::class_<pyDia::Exception, python::bases<DbgException> > diaException( 
-        "DiaException", "Debug interface access exception",
-        python::no_init );
+        "DiaException", "Debug interface access exception", python::no_init);
     diaException
-        .def( "hres", &pyDia::Exception::getRes );
+        .def( "hres", &pyDia::Exception::getRes )
+        _DECL_BASE_EXCEPT_STR;
     pyDia::Exception::setTypeObject( diaException.ptr() );
     python::register_exception_translator<pyDia::Exception>( 
         &pyDia::Exception::exceptionTranslate );
diff --git a/pykd/dbgobj.h b/pykd/dbgobj.h
index cdeebbc..4b809c0 100644
--- a/pykd/dbgobj.h
+++ b/pykd/dbgobj.h
@@ -2,6 +2,7 @@
 
 #include <dbgeng.h>
 #include "dbgexcept.h"
+#include "synsymbol.h"
 
 namespace pykd {
 
@@ -11,7 +12,8 @@ class DbgObject {
 
 protected:
 
-    DbgObject( IDebugClient4 *client ) {
+    DbgObject( IDebugClient4 *client )
+    {
 
         m_client = client;
 
@@ -38,7 +40,7 @@ protected:
 
         hres = client->QueryInterface( __uuidof(IDebugRegisters2), (void**)&m_registers );
         if ( FAILED( hres ) )
-            throw DbgException("QueryInterface IDebugDataSpaces  failed"); 
+            throw DbgException("QueryInterface IDebugDataSpaces  failed");
     }
     
     virtual ~DbgObject() {};
@@ -50,7 +52,6 @@ protected:
     CComPtr<IDebugAdvanced2>    m_advanced;
     CComPtr<IDebugDataSpaces4>  m_dataSpaces;
     CComPtr<IDebugRegisters2>   m_registers;
-
 };
 
 
diff --git a/pykd/inteventhandler.cpp b/pykd/inteventhandler.cpp
new file mode 100644
index 0000000..90fd97d
--- /dev/null
+++ b/pykd/inteventhandler.cpp
@@ -0,0 +1,76 @@
+
+#include "stdafx.h"
+
+#include "inteventhandler.h"
+#include "dbgexcept.h"
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+InternalDbgEventHandler::InternalDbgEventHandler(
+    IDebugClient4 *client,
+    SynSymbolsPtr synSymbols
+)   : m_synSymbols(synSymbols)
+{
+    HRESULT hres = client->CreateClient(&m_client);
+    if (FAILED(hres))
+        throw DbgException("Call IDebugClient::CreateClient failed");
+
+    m_client->SetEventCallbacks(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+InternalDbgEventHandler::~InternalDbgEventHandler()
+{
+    m_client->Release();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+HRESULT InternalDbgEventHandler::GetInterestMask(
+    __out PULONG Mask
+)
+{
+    *Mask = 
+        DEBUG_EVENT_CHANGE_SYMBOL_STATE;
+
+    return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+HRESULT InternalDbgEventHandler::ChangeSymbolState(
+    __in ULONG Flags,
+    __in ULONG64 Argument
+)
+{
+    HRESULT hres = S_OK;
+
+    if (DEBUG_CSS_LOADS & Flags)
+        hres = symLoaded(Argument);
+
+    return hres;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+HRESULT InternalDbgEventHandler::symLoaded(
+    __in ULONG64 ModuleAddress
+)
+{
+    if (!ModuleAddress)
+    {
+        // f.e. is case ".reload /f image.exe", if for image.exe no symbols
+        m_synSymbols->restoreAll();
+        return S_OK;
+    }
+
+    m_synSymbols->restoreForModule(ModuleAddress);
+    return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+};  // namespace pykd
diff --git a/pykd/inteventhandler.h b/pykd/inteventhandler.h
new file mode 100644
index 0000000..366b5c0
--- /dev/null
+++ b/pykd/inteventhandler.h
@@ -0,0 +1,45 @@
+// 
+// Internal debug event handler
+// 
+
+#pragma once
+
+#include <DbgEng.h>
+#include "synsymbol.h"
+
+namespace pykd {
+
+class InternalDbgEventHandler : public DebugBaseEventCallbacks {
+public:
+
+    InternalDbgEventHandler(
+        IDebugClient4 *client,
+        SynSymbolsPtr synSymbols
+    );
+    ~InternalDbgEventHandler();
+
+protected:
+
+    // IUnknown impls
+    STDMETHOD_(ULONG, AddRef)() { return 1; }
+    STDMETHOD_(ULONG, Release)() { return 1; }
+
+    // IDebugEventCallbacks impls
+    STDMETHOD(GetInterestMask)(
+        __out PULONG Mask
+    );
+
+    STDMETHOD(ChangeSymbolState)(
+        __in ULONG Flags,
+        __in ULONG64 Argument
+    );
+
+private:
+
+    HRESULT symLoaded(__in ULONG64 ModuleAddress);
+
+    IDebugClient *m_client;
+    SynSymbolsPtr m_synSymbols;
+};
+
+};  // namespace pykd
diff --git a/pykd/module.cpp b/pykd/module.cpp
index 52733c9..3d7e0af 100644
--- a/pykd/module.cpp
+++ b/pykd/module.cpp
@@ -20,7 +20,9 @@ Module loadModuleByOffset( ULONG64  offset ) {
 
 ///////////////////////////////////////////////////////////////////////////////////
 
-Module::Module( IDebugClient4 *client, const std::string& moduleName ) : DbgObject( client )
+Module::Module( IDebugClient4 *client, SynSymbolsPtr synSymbols, const std::string& moduleName ) 
+    : DbgObject( client )
+    , m_synSymbols(synSymbols)
 {
     HRESULT    hres;
 
@@ -36,6 +38,8 @@ Module::Module( IDebugClient4 *client, const std::string& moduleName ) : DbgObje
          throw DbgException( "IDebugSymbol::GetModuleParameters  failed" );    
 
     m_size = moduleParam.Size;
+    m_timeDataStamp = moduleParam.TimeDateStamp;
+    m_checkSumm = moduleParam.Checksum;
 
     char imageName[0x100];
 
@@ -55,7 +59,9 @@ Module::Module( IDebugClient4 *client, const std::string& moduleName ) : DbgObje
 
 ///////////////////////////////////////////////////////////////////////////////////
 
-Module::Module( IDebugClient4 *client, ULONG64 offset ) : DbgObject( client )
+Module::Module( IDebugClient4 *client, SynSymbolsPtr synSymbols, ULONG64 offset ) 
+    : DbgObject( client )
+    , m_synSymbols(synSymbols)
 {
     HRESULT     hres;
 
@@ -102,6 +108,8 @@ Module::Module( IDebugClient4 *client, ULONG64 offset ) : DbgObject( client )
          throw DbgException( "IDebugSymbol::GetModuleParameters  failed" );    
 
     m_size = moduleParam.Size;
+    m_timeDataStamp = moduleParam.TimeDateStamp;
+    m_checkSumm = moduleParam.Checksum;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////
@@ -198,5 +206,18 @@ Module::getTypedVarByAddr( ULONG64 addr )
 
 ///////////////////////////////////////////////////////////////////////////////////
 
+ULONG Module::getRvaByName(const std::string &symName)
+{
+    try {
+        pyDia::SymbolPtr sym = getDia()->getChildByName( symName );
+        return sym->getRva();
+    } 
+    catch (const pyDia::Exception &) {
+    }
+    return (ULONG)m_synSymbols->getRvaByName(m_timeDataStamp, m_checkSumm, symName);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
 }; // end of namespace pykd
 
diff --git a/pykd/module.h b/pykd/module.h
index 73e3648..f6737f3 100644
--- a/pykd/module.h
+++ b/pykd/module.h
@@ -6,6 +6,7 @@
 #include "diawrapper.h"
 #include "typeinfo.h"
 #include "typedvar.h"
+#include "synsymbol.h"
 
 namespace pykd {
 
@@ -15,9 +16,9 @@ class Module : private DbgObject {
 
 public:
     
-    Module( IDebugClient4 *client, const std::string& moduleName );
+    Module( IDebugClient4 *client, SynSymbolsPtr synSymbols, const std::string& moduleName );
 
-    Module( IDebugClient4 *client, ULONG64 offset );
+    Module( IDebugClient4 *client, SynSymbolsPtr synSymbols, ULONG64 offset );
 
     std::string  getName() {
         return m_name;
@@ -47,16 +48,12 @@ public:
    
     ULONG64
     getSymbol( const std::string &symbolname ) {
-        pyDia::SymbolPtr   sym = getDia()->getChildByName( symbolname );
-
-        return m_base + sym->getRva();
+        return m_base + getRvaByName(symbolname);
     }
 
     ULONG
     getSymbolRva( const std::string &symbolname ) {
-        pyDia::SymbolPtr   sym = getDia()->getChildByName( symbolname );
-
-        return sym->getRva();
+        return getRvaByName(symbolname);
     }
 
     TypeInfoPtr getTypeByName( const std::string &typeName ) {
@@ -73,6 +70,8 @@ public:
 
 private:
 
+    ULONG getRvaByName(const std::string &symName);
+
     pyDia::GlobalScopePtr& getDia() {
         if (!m_dia)
             m_dia = pyDia::GlobalScope::loadPdb( getPdbName() );
@@ -84,7 +83,12 @@ private:
     std::string             m_imageName;
     ULONG64                 m_base;
     ULONG                   m_size;
+
     pyDia::GlobalScopePtr   m_dia;
+
+    ULONG                   m_timeDataStamp;
+    ULONG                   m_checkSumm;
+    SynSymbolsPtr           m_synSymbols;
 };
 
 ///////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj
index 3bf7832..157b1c9 100644
--- a/pykd/pykd_2008.vcproj
+++ b/pykd/pykd_2008.vcproj
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="windows-1251"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="9,00"
+	Version="9.00"
 	Name="pykd"
 	ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
 	RootNamespace="pykd"
@@ -401,6 +401,10 @@
 				RelativePath=".\disasm.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\inteventhandler.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\module.cpp"
 				>
@@ -445,6 +449,14 @@
 					/>
 				</FileConfiguration>
 			</File>
+			<File
+				RelativePath=".\synsymbol.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\synsymhelpers.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\typedvar.cpp"
 				>
@@ -511,6 +523,10 @@
 				RelativePath=".\intbase.h"
 				>
 			</File>
+			<File
+				RelativePath=".\inteventhandler.h"
+				>
+			</File>
 			<File
 				RelativePath=".\module.h"
 				>
@@ -527,6 +543,14 @@
 				RelativePath=".\stdafx.h"
 				>
 			</File>
+			<File
+				RelativePath=".\synsymbol.h"
+				>
+			</File>
+			<File
+				RelativePath=".\synsymhelpers.h"
+				>
+			</File>
 			<File
 				RelativePath=".\typedvar.h"
 				>
diff --git a/pykd/synsymbol.cpp b/pykd/synsymbol.cpp
new file mode 100644
index 0000000..75c40db
--- /dev/null
+++ b/pykd/synsymbol.cpp
@@ -0,0 +1,248 @@
+
+#include "stdafx.h"
+
+#include <boost/algorithm/string.hpp>
+
+#include "dbgmem.h"
+#include "dbgexcept.h"
+#include "dbgclient.h"
+#include "synsymhelpers.h"
+
+namespace pykd {
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+SyntheticSymbols::SyntheticSymbols(
+    IDebugSymbols3 &symbols,
+    DebugClient &dbgClient
+)   : m_symbols(symbols)
+    , m_dbgClient(dbgClient)
+{
+    m_allSymbolsLock.reset(new boost::recursive_mutex);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::add(
+    ULONG64 addr,
+    ULONG size,
+    const std::string &symName
+)
+{
+    addr = m_dbgClient.addr64(addr);
+
+    // add new synthetic symbol to debug engine
+    DEBUG_MODULE_AND_ID dbgModuleAndId = { 0 };
+    HRESULT hres = 
+        m_symbols.AddSyntheticSymbol(
+            addr,
+            size,
+            symName.c_str(),
+            DEBUG_ADDSYNTHSYM_DEFAULT,
+            &dbgModuleAndId);
+    if ( FAILED( hres ) )
+        throw DbgException(buildExceptDesc("IDebugSymbols3::AddSyntheticSymbol", hres));
+
+    // add/update symbol for target module (in internal map)
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+
+    ModSymbols &modSymbols = 
+        m_allSymbols[SynSymHelper(m_symbols).modByBase(dbgModuleAndId.ModuleBase)];
+    SymbolData &symData = modSymbols[addr - dbgModuleAndId.ModuleBase];
+
+    symData.m_name = symName;
+    symData.m_size = size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG SyntheticSymbols::remove(ULONG64 addr)
+{
+    addr = m_dbgClient.addr64(addr);
+
+    SynSymHelper synSymHelper(m_symbols);
+
+    // find target module
+    ULONG64 moduleBase;
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+    AllSymbols::iterator itModSymbols = 
+        m_allSymbols.find(synSymHelper.modByOffset(addr, moduleBase));
+    if (itModSymbols == m_allSymbols.end())
+        return 0;
+
+    // remove symbol from internal map
+    itModSymbols->second.erase(addr - moduleBase);
+
+    // remove symbol from debug engine
+    return synSymHelper.removeSyntheticSymbols(addr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG SyntheticSymbols::removeByMask(
+    const std::string &moduleName,
+    const std::string &symName
+)
+{
+    SynSymHelper synSymHelper(m_symbols);
+
+    std::vector<DEBUG_MODULE_AND_ID> dbgSymbols;
+    HRESULT hres = 
+        synSymHelper.getSymbolsByMaks(
+            moduleName + "!" + symName,
+            dbgSymbols);
+    if (FAILED(hres))
+        throw DbgException(buildExceptDesc("IDebugSymbols3::GetSymbolEntriesByName", hres));
+
+    if (dbgSymbols.empty())
+        return 0;
+
+    ULONG removed = 0;
+
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+    for (ULONG i =0; i < dbgSymbols.size(); ++i)
+    {
+        DEBUG_SYMBOL_ENTRY dbgSymbolInfo;
+        HRESULT hres = 
+            m_symbols.GetSymbolEntryInformation(
+                &dbgSymbols[i],
+                &dbgSymbolInfo);
+        if (FAILED(hres))
+            continue;
+
+        // try find modules in internal map
+        AllSymbols::iterator itModSymbols = 
+            m_allSymbols.find(synSymHelper.modByBase(dbgSymbolInfo.ModuleBase));
+        if (itModSymbols == m_allSymbols.end())
+            continue;
+
+        // try find symbol
+        ModSymbols::iterator itSymbol = 
+            itModSymbols->second.find(dbgSymbolInfo.Offset - dbgSymbolInfo.ModuleBase);
+        if (itSymbol == itModSymbols->second.end())
+            continue;
+
+        // remove from debug engine
+        if (synSymHelper.removeSyntheticSymbols(dbgSymbols[i]))
+            ++removed;
+
+        // remove from internal map
+        itModSymbols->second.erase(itSymbol);
+
+        if (itModSymbols->second.empty())
+            m_allSymbols.erase(itModSymbols);
+    }
+
+    return removed;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::clear()
+{
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+
+    // clean symbols from debug engine
+    forEachLoadedModule( SynSymRemoveAll(m_symbols) );
+
+    // clean internal map
+    m_allSymbols.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::restoreForModule(ULONG64 moduleBase)
+{
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+
+    SynSymRestore restorer(m_symbols);
+    AllSymbols::iterator itFoundModule = 
+        m_allSymbols.find( restorer.modByBase(moduleBase) );
+    if (itFoundModule == m_allSymbols.end())
+        return;
+
+    forEachFromModule(moduleBase, itFoundModule->second, restorer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::restoreAll()
+{
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+
+    // clean symbols from debug engine
+    forEachLoadedModule( SynSymRestore(m_symbols) );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG64 SyntheticSymbols::getRvaByName(
+    ULONG timeDataStamp,
+    ULONG checkSumm,
+    const std::string &symName
+)
+{
+    SymbolsScopedLock lock(*m_allSymbolsLock);
+    AllSymbols::iterator itFoundModule = 
+        m_allSymbols.find( ModuleId(timeDataStamp, checkSumm) );
+    if (itFoundModule == m_allSymbols.end())
+        throw DbgException("Synthetic symbol is not found");
+
+
+    ModSymbols::iterator itSynSymbol = itFoundModule->second.begin();
+    while (itSynSymbol != itFoundModule->second.end())
+    {
+        if (boost::iequals(symName, itSynSymbol->second.m_name))
+            return itSynSymbol->first;
+
+        ++itSynSymbol;
+    }
+    throw DbgException("Synthetic symbol is not found");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::forEachFromModule(
+    ULONG64 moduleBase,
+    const ModSymbols &modSymbols,
+    ISynSymForEach &forEach
+)
+{
+    ModSymbols::const_iterator itSynSymbol = modSymbols.begin();
+    while (itSynSymbol != modSymbols.end())
+    {
+        forEach.symbol(moduleBase, itSynSymbol->first, itSynSymbol->second);
+        ++itSynSymbol;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SyntheticSymbols::forEachLoadedModule(ISynSymForEach &forEach)
+{
+    // for loaded and unloaded modules...
+    std::vector<DEBUG_MODULE_PARAMETERS> dbgModules;
+    if (!SUCCEEDED(forEach.getAllModules(dbgModules)) || dbgModules.empty())
+    {
+        SymbolsScopedLock lock(*m_allSymbolsLock);
+        m_allSymbols.clear();
+        return;
+    }
+
+    std::vector<DEBUG_MODULE_PARAMETERS>::iterator itModule = dbgModules.begin();
+    while (itModule != dbgModules.end())
+    {
+        // ...do it!
+        AllSymbols::const_iterator itFoundModule = 
+            m_allSymbols.find( ModuleId(*itModule) );
+        if (itFoundModule != m_allSymbols.end())
+            forEachFromModule(itModule->Base, itFoundModule->second, forEach);
+
+        ++itModule;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+};  // namespace pykd
diff --git a/pykd/synsymbol.h b/pykd/synsymbol.h
new file mode 100644
index 0000000..a461631
--- /dev/null
+++ b/pykd/synsymbol.h
@@ -0,0 +1,144 @@
+// 
+// Synthetic symbol
+// 
+
+#pragma once
+
+#include "dbgexcept.h"
+#include <DbgEng.h>
+#include <map>
+#include <boost\thread\win32\recursive_mutex.hpp>
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+interface ISynSymForEach;
+class DebugClient;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class SyntheticSymbols {
+public:
+    SyntheticSymbols(
+        IDebugSymbols3 &symbols,
+        DebugClient &dbgClient
+    );
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Python API:
+
+    // add new synthetic symbol
+    void add(
+        ULONG64 addr,
+        ULONG size,
+        const std::string &symName
+    );
+
+    // remove synthetic symbols by address
+    ULONG remove(ULONG64 addr);
+
+    // remove synthetic symbols by module and symbol names
+    ULONG removeByMask(
+        const std::string &moduleName,
+        const std::string &symName
+    );
+
+    // remove all synthetic symbols from all modules
+    void clear();
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Debug event callback manager API:
+
+    void restoreForModule(ULONG64 moduleBase);
+    void restoreAll();
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Module API:
+
+    ULONG64 getRvaByName(
+        ULONG timeDataStamp,
+        ULONG checkSumm,
+        const std::string &symName
+    );
+
+public:
+
+    // unique module ID
+    struct ModuleId {
+        ULONG m_timeDataStamp;
+        ULONG m_checkSumm;
+
+        ModuleId(ULONG timeDataStamp, ULONG checkSumm)
+            : m_timeDataStamp(timeDataStamp)
+            , m_checkSumm(checkSumm)
+        {
+        }
+
+        ModuleId(const DEBUG_MODULE_PARAMETERS &dbgModuleParameters)
+            : m_timeDataStamp(dbgModuleParameters.TimeDateStamp)
+            , m_checkSumm(dbgModuleParameters.Checksum)
+        {
+        }
+
+        bool operator == (const ModuleId &rhs) const
+        {
+            return 
+                m_timeDataStamp == rhs.m_timeDataStamp &&
+                m_checkSumm == rhs.m_checkSumm;
+        }
+        bool operator < (const ModuleId &rhs) const
+        {
+            return 
+                m_timeDataStamp < rhs.m_timeDataStamp &&
+                m_checkSumm < rhs.m_checkSumm;
+        }
+    };
+
+    // symbol data
+    struct SymbolData {
+        std::string m_name;
+        ULONG m_size;
+    };
+
+    // synthetic symbols of one module: offset -> name+size
+    typedef ULONG64 SYM_OFFSET;
+    typedef std::map<SYM_OFFSET, SymbolData> ModSymbols;
+
+    // synthetic symbols of all modules
+    typedef std::map<ModuleId, ModSymbols> AllSymbols;
+
+private:
+
+    // lock of static map
+    typedef boost::shared_ptr<boost::recursive_mutex> SymbolsLock;
+    typedef boost::recursive_mutex::scoped_lock SymbolsScopedLock;
+
+private:
+
+    // execute for all symbols from modules
+    void forEachFromModule(
+        ULONG64 moduleBase,
+        const ModSymbols &modSymbols,
+        ISynSymForEach &forEach
+    );
+
+    // execute for all symbols all loaded modules
+    void forEachLoadedModule(ISynSymForEach &forEach);
+
+private:
+
+    SymbolsLock m_allSymbolsLock;
+    AllSymbols m_allSymbols;
+
+    DebugClient &m_dbgClient;
+    IDebugSymbols3 &m_symbols;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+typedef boost::shared_ptr<SyntheticSymbols> SynSymbolsPtr;
+
+////////////////////////////////////////////////////////////////////////////////
+
+};  // namespace pykd
diff --git a/pykd/synsymhelpers.cpp b/pykd/synsymhelpers.cpp
new file mode 100644
index 0000000..8f1b067
--- /dev/null
+++ b/pykd/synsymhelpers.cpp
@@ -0,0 +1,152 @@
+
+#include <stdafx.h>
+
+#include "dbgexcept.h"
+#include "synsymhelpers.h"
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SynSymHelper::removeSyntheticSymbols(
+    const DEBUG_MODULE_AND_ID &dbgSymbols
+)
+{
+    return SUCCEEDED(
+        m_symbols.RemoveSyntheticSymbol(
+            const_cast<DEBUG_MODULE_AND_ID *>(&dbgSymbols)
+        )
+    );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG SynSymHelper::removeSyntheticSymbols(
+    const std::vector<DEBUG_MODULE_AND_ID> &arrSymbols
+)
+{
+    ULONG countOfRemoved = 0;
+    for (ULONG i = 0; i < arrSymbols.size(); ++i)
+    {
+        if (removeSyntheticSymbols(arrSymbols[i]))
+            ++countOfRemoved;
+    }
+    return countOfRemoved;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG SynSymHelper::removeSyntheticSymbols(ULONG64 addr)
+{
+    ULONG entries = 0;
+    m_symbols.GetSymbolEntriesByOffset(addr, 0, NULL, NULL, 0, &entries);
+    if (!entries)
+        return 0;
+
+    std::vector<DEBUG_MODULE_AND_ID> arrSymbols(entries);
+    HRESULT hres = m_symbols.GetSymbolEntriesByOffset(
+        addr,
+        0,
+        &arrSymbols[0],
+        NULL,
+        (ULONG)arrSymbols.size(),
+        NULL);
+    if (SUCCEEDED(hres))
+        return removeSyntheticSymbols(arrSymbols);
+
+    return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SyntheticSymbols::ModuleId SynSymHelper::modByBase(ULONG64 moduleBase)
+{
+    DEBUG_MODULE_PARAMETERS dbgModuleParameters;
+    HRESULT hres = 
+        m_symbols.GetModuleParameters(
+            1,
+            &moduleBase,
+            0,
+            &dbgModuleParameters);
+    if ( FAILED( hres ) )
+        throw DbgException(buildExceptDesc("IDebugSymbols3::GetModuleParameters", hres));
+
+    return SyntheticSymbols::ModuleId(dbgModuleParameters);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SyntheticSymbols::ModuleId SynSymHelper::modByOffset(
+    ULONG64 moduleOffset,
+    ULONG64 &moduleBase
+)
+{
+    HRESULT hres = 
+        m_symbols.GetModuleByOffset(moduleOffset, 0, NULL, &moduleBase);
+    if ( FAILED( hres ) )
+        throw DbgException(buildExceptDesc("IDebugSymbols3::GetModuleByOffset", hres));
+
+    return modByBase(moduleBase);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+HRESULT SynSymHelper::getAllModules(
+    std::vector<DEBUG_MODULE_PARAMETERS> &dbgModules
+)
+{
+    ULONG nLoaded;
+    ULONG nUnloaded;
+    HRESULT hres = m_symbols.GetNumberModules(&nLoaded, &nUnloaded);
+    if (FAILED(hres))
+        return hres;
+
+    if (!nLoaded && !nUnloaded)
+    {
+        dbgModules.clear();
+        return S_OK;
+    }
+
+    dbgModules.resize(nLoaded + nUnloaded);
+    return 
+        m_symbols.GetModuleParameters(
+            nLoaded + nUnloaded,
+            NULL,
+            0,
+            &dbgModules[0]);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+HRESULT SynSymHelper::getSymbolsByMaks(
+    const std::string &symMask,
+    std::vector<DEBUG_MODULE_AND_ID> &dbgSymbols
+)
+{
+    ULONG entries = 0;
+    m_symbols.GetSymbolEntriesByName(
+        symMask.c_str(),
+        0,
+        NULL,
+        0,
+        &entries);
+    if (!entries)
+    {
+        dbgSymbols.clear();
+        return S_OK;
+    }
+
+    dbgSymbols.resize(entries);
+
+    return 
+        m_symbols.GetSymbolEntriesByName(
+            symMask.c_str(),
+            0,
+            &dbgSymbols[0],
+            entries,
+            NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+};  // namespace pykd
diff --git a/pykd/synsymhelpers.h b/pykd/synsymhelpers.h
new file mode 100644
index 0000000..f3e4f48
--- /dev/null
+++ b/pykd/synsymhelpers.h
@@ -0,0 +1,107 @@
+// 
+// Synthetic symbol helpers
+// 
+
+#pragma once
+
+#include <vector>
+
+#include "synsymbol.h"
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class SynSymHelper {
+public:
+    SynSymHelper(IDebugSymbols3 &symbols) : m_symbols(symbols) {}
+
+    // remove array of synthetic symbols from debug engine
+    bool removeSyntheticSymbols(
+        const DEBUG_MODULE_AND_ID &dbgSymbols
+    );
+    ULONG removeSyntheticSymbols(
+        const std::vector<DEBUG_MODULE_AND_ID> &arrSymbols
+    );
+    ULONG removeSyntheticSymbols(ULONG64 addr);
+
+    // buid ModuleId by base of image
+    SyntheticSymbols::ModuleId modByBase(ULONG64 moduleBase);
+
+    // buid ModuleId by offset in image
+    SyntheticSymbols::ModuleId modByOffset(
+        ULONG64 moduleOffset,
+        ULONG64 &moduleBase
+    );
+
+    // get array of all modules
+    HRESULT getAllModules(std::vector<DEBUG_MODULE_PARAMETERS> &dbgModules);
+
+    // get symbols by mask
+    HRESULT getSymbolsByMaks(
+        const std::string &symMask,
+        std::vector<DEBUG_MODULE_AND_ID> &dbgSymbols
+    );
+
+protected:
+    IDebugSymbols3 &m_symbols;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Enumerator all synthetic symbols for loaded modules
+////////////////////////////////////////////////////////////////////////////////
+interface ISynSymForEach : public SynSymHelper {
+    ISynSymForEach(IDebugSymbols3 &symbols) : SynSymHelper(symbols) {}
+
+    virtual void symbol(
+        const ULONG64 moduleBase,
+        SyntheticSymbols::SYM_OFFSET offset,
+        const SyntheticSymbols::SymbolData &symData
+    ) = 0;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Remove symbols from loaded modules
+////////////////////////////////////////////////////////////////////////////////
+class SynSymRemoveAll : public ISynSymForEach
+{
+public:
+    SynSymRemoveAll(IDebugSymbols3 &symbols) : ISynSymForEach(symbols) {}
+
+    virtual void symbol(
+        const ULONG64 moduleBase,
+        SyntheticSymbols::SYM_OFFSET offset,
+        const SyntheticSymbols::SymbolData &/*symData*/
+    ) override
+    {
+        removeSyntheticSymbols(moduleBase + offset);
+    }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Restore symbols for loaded modules
+////////////////////////////////////////////////////////////////////////////////
+class SynSymRestore : public ISynSymForEach
+{
+public:
+    SynSymRestore(IDebugSymbols3 &symbols) : ISynSymForEach(symbols) {}
+
+    virtual void symbol(
+        const ULONG64 moduleBase,
+        SyntheticSymbols::SYM_OFFSET offset,
+        const SyntheticSymbols::SymbolData &symData
+    ) override
+    {
+        m_symbols.AddSyntheticSymbol(
+            moduleBase + offset,
+            symData.m_size,
+            symData.m_name.c_str(),
+            DEBUG_ADDSYNTHSYM_DEFAULT,
+            NULL);
+    }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+};  // namespace pykd
diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py
index 61793ed..8220b5d 100644
--- a/test/scripts/pykdtest.py
+++ b/test/scripts/pykdtest.py
@@ -22,6 +22,7 @@ import eventtest
 import typedvar
 import memtest
 import intbase
+import synsymtest
 
 def getTestSuite( singleName = "" ):
     if singleName == "":
@@ -36,6 +37,7 @@ def getTestSuite( singleName = "" ):
                unittest.TestLoader().loadTestsFromTestCase( eventtest.EventTest ),
                unittest.TestLoader().loadTestsFromTestCase( memtest.MemoryTest ),
                unittest.TestLoader().loadTestsFromTestCase( intbase.IntBaseTest ),
+               unittest.TestLoader().loadTestsFromTestCase( synsymtest.SynSymTest )
            ] ) 
     else:
        return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) )
@@ -58,5 +60,5 @@ if __name__ == "__main__":
     #suite = getTestSuite( "typedvar.TypedVarTest.testStruct" )    
    
     unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( suite )
-    
-    #a = raw_input("\npress return\n")
\ No newline at end of file
+
+    a = raw_input("\npress return\n")
\ No newline at end of file
diff --git a/test/scripts/synsymtest.py b/test/scripts/synsymtest.py
new file mode 100644
index 0000000..ab768cd
--- /dev/null
+++ b/test/scripts/synsymtest.py
@@ -0,0 +1,68 @@
+"""Synthetic symbols tests"""
+
+import unittest
+import target
+import pykd
+
+class SynSymTest(unittest.TestCase):
+    """Unit tests of synthetic symbols"""
+
+    def testAdd(self):
+        """Add new synthetic symbol"""
+        pykd.addSynSymbol(
+            target.module.offset("FuncWithName0")-1, 1, "synSym1")
+        self.assertEqual(
+            target.module.offset("FuncWithName0")-1,
+            target.module.offset("synSym1"))
+
+    def testDel(self):
+        """Remove synthetic symbol"""
+        pykd.addSynSymbol(
+            target.module.offset("FuncWithName0")-2, 1, "synSym2")
+        self.assertEqual(
+            pykd.delSynSymbol( target.module.offset("synSym2") ), 1 )
+
+        exceptionOccurred = True
+        try:
+            target.module.rva("synSym2")
+            exceptionOccurred = False
+        except pykd.BaseException:
+            pass
+        self.assertTrue(exceptionOccurred)
+
+    def testDelAll(self):
+        """Remove all synthetic symbols"""
+        pykd.addSynSymbol(
+            target.module.offset("FuncWithName0")-3, 1, "synSym3")
+        pykd.delAllSynSymbols()
+
+        exceptionOccurred = True
+        try:
+            target.module.rva("synSym3")
+            exceptionOccurred = False
+        except pykd.BaseException:
+            pass
+        self.assertTrue(exceptionOccurred)
+
+    def testDelByMask(self):
+        """Remove synthetic symbol by mask"""
+        pykd.addSynSymbol(
+            target.module.offset("FuncWithName0")-4, 1, "synSym4")
+        self.assertTrue( pykd.delSynSymbolsMask( "*", "synSym4" ) >= 1 )
+
+        exceptionOccurred = True
+        try:
+            target.module.rva("synSym4")
+            exceptionOccurred = False
+        except pykd.BaseException:
+            pass
+        self.assertTrue(exceptionOccurred)
+
+    def testReload(self):
+        """Restore synthetic symbols after reload module symbols"""
+        pykd.addSynSymbol(
+            target.module.offset("FuncWithName0")-5, 1, "synSym5")
+        target.module.reload()
+        self.assertEqual(
+            target.module.offset("FuncWithName0")-5,
+            target.module.offset("synSym5"))
diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj
index 4f61382..03cd77b 100644
--- a/test/targetapp/targetapp.vcproj
+++ b/test/targetapp/targetapp.vcproj
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="windows-1251"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="9,00"
+	Version="9.00"
 	Name="targetapp"
 	ProjectGUID="{C6254E16-AB8E-41EE-887D-31458E93FC68}"
 	RootNamespace="targetapp"
@@ -440,6 +440,10 @@
 				RelativePath="..\scripts\regtest.py"
 				>
 			</File>
+			<File
+				RelativePath="..\scripts\synsymtest.py"
+				>
+			</File>
 			<File
 				RelativePath="..\scripts\target.py"
 				>