コード例 #1
0
ファイル: sildasm.cpp プロジェクト: BikS2013/coreclr
HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr)
{
    HRESULT Status = S_OK;

    ULONG Size = GetILSize(ilAddr);
    if (Size == 0)
    {
        ExtOut("error decoding IL\n");
        return Status;
    }

    ExtOut("ilAddr = %p\n", (ULONG64) ilAddr);

    // Read the memory into a local buffer
    ArrayHolder<BYTE> pArray = new BYTE[Size];
    Status = g_ExtData->ReadVirtual(TO_CDADDR(ilAddr), pArray, Size, NULL);
    if (Status != S_OK)
    {
        ExtOut("Failed to read memory\n");
        return Status;
    }

    DecodeIL(pImport, pArray, Size);

    return Status;
}
コード例 #2
0
ファイル: dbgexts.cpp プロジェクト: cutepig123/TestWindbg
void
ExtExec(PCSTR Command)
{
	ExtOut("Exec: %s\n", Command);
    g_ExtControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, Command,DEBUG_EXECUTE_DEFAULT);
	//g_ExtControl->Execute(DEBUG_OUTCTL_LOG_ONLY, Command,DEBUG_EXECUTE_DEFAULT);
}
コード例 #3
0
ファイル: disasm.cpp プロジェクト: blackdwarf/coreclr
char* PrintOneLine (__in_z char *begin, __in_z char *limit)
{
    if (begin == NULL || begin >= limit) {
        return NULL;
    }
    char line[128];
    size_t length;
    char *end;
    while (1) {
        if (IsInterrupt())
            return NULL;
        length = strlen (begin);
        end = strstr (begin, "\r\xa");
        if (end == NULL) {
            ExtOut ("%s", begin);
            end = begin+length+1;
            if (end >= limit) {
                return NULL;
            }
        }
        else {
            end += 2;
            length = end-begin;
            while (length) {
                if (IsInterrupt())
                    return NULL;
                size_t n = length;
                if (n > 127) {
                    n = 127;
                }
                strncpy_s (line,_countof(line), begin, n);
                line[n] = '\0';
                ExtOut ("%s", line);
                begin += n;
                length -= n;
            }
            return end;
        }
    }
}
コード例 #4
0
ファイル: dbgcb.cpp プロジェクト: BwRy/ioctlfuzzer
void ExtCleanup(void)
{
    /**
     * clean up any resources
     */

    ExtOut(__FUNCTION__"()\n");

    if (g_DataSpaces)
    {
        g_DataSpaces->Release();
    }

    if (g_Registers)
    {
        g_Registers->Release();
    }

    if (g_Control)
    {
        g_Control->Release();
    }

    if (g_Symbols)
    {
        g_Symbols->Release();
    }

    if (g_SystemObjects)
    {
        g_SystemObjects->Release();
    }
    
    if (g_Client)
    {
        g_Client->Release();
    } 
}
コード例 #5
0
ファイル: WatchCmd.cpp プロジェクト: 0-wiz-0/coreclr
// Evaluates and prints a tree version of the active watch list
// The tree will be expanded along the nodes in expansionPath
// Optionally the list is filtered to only show differences from pFilterName (the name of a persisted watch list)
HRESULT WatchCmd::Print(int expansionIndex, __in_z WCHAR* expansionPath, __in_z WCHAR* pFilterName)
{
    HRESULT Status = S_OK;
    INIT_API_EE();
    INIT_API_DAC();
    EnableDMLHolder dmlHolder(TRUE);
    IfFailRet(InitCorDebugInterface());

    PersistList* pFilterList = NULL;
    if(pFilterName != NULL)
    {
        pFilterList = pPersistListHead;
        while(pFilterList != NULL)
        {
            if(_wcscmp(pFilterList->pName, pFilterName)==0)
                break;
            pFilterList = pFilterList->pNext;
        }
    }

    PersistWatchExpression* pHeadFilterExpr = (pFilterList != NULL) ? pFilterList->pHeadExpr : NULL;

    WatchExpression* pExpression = pExpressionListHead;
    int index = 1;
    while(pExpression != NULL)
    {
        ExpressionNode* pResult = NULL;
        if(FAILED(Status = ExpressionNode::CreateExpressionNode(pExpression->pExpression, &pResult)))
        {
            ExtOut("  %d) Error: HRESULT 0x%x while evaluating expression \'%S\'", index, Status, pExpression->pExpression);
        }
        else
        {
            //check for matching absolute expression
            PersistWatchExpression* pCurFilterExpr = pHeadFilterExpr;
            while(pCurFilterExpr != NULL)
            {
                if(_wcscmp(pCurFilterExpr->pExpression, pResult->GetAbsoluteExpression())==0)
                    break;
                pCurFilterExpr = pCurFilterExpr->pNext;
            }

            // check for matching persist evaluation on the matching expression
            BOOL print = TRUE;
            if(pCurFilterExpr != NULL)
            {
                WCHAR pCurPersistResult[MAX_EXPRESSION];
                FormatPersistResult(pCurPersistResult, MAX_EXPRESSION, pResult);
                if(_wcscmp(pCurPersistResult, pCurFilterExpr->pPersistResult)==0)
                {
                    print = FALSE;
                }
            }

            //expand and print
            if(print)
            {
                if(index == expansionIndex)
                    pResult->Expand(expansionPath);
                PrintCallbackData data;
                data.index = index;
                WCHAR pCommand[MAX_EXPRESSION];
                swprintf_s(pCommand, MAX_EXPRESSION, L"!watch -expand %d", index);
                data.pCommand = pCommand;
                pResult->DFSVisit(EvalPrintCallback, (VOID*)&data);
            }
            delete pResult;
        }
        pExpression = pExpression->pNext;
        index++;
    }
    return Status;
}
コード例 #6
0
ファイル: disasm.cpp プロジェクト: blackdwarf/coreclr
void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
{
    char            filename[MAX_PATH_FNAME+1];
    char            line[256];
    int             lcount          = 10;

    ULONG linenum = 0;
    ULONG64 Displacement = 0;
    BOOL fLineAvailable = FALSE;
    ULONG64 vIP = 0;
    
    if (!bSuppressLines)
    {
        ReloadSymbolWithLineInfo();
        fLineAvailable = SUCCEEDED (g_ExtSymbols->GetLineByOffset (TO_CDADDR(IP), &linenum,
                                                                    filename,
                                                                    MAX_PATH_FNAME+1,
                                                                    NULL,
                                                                    &Displacement));
    }
    ULONG FileLines = 0;
    ArrayHolder<ULONG64> Buffer = NULL;

    if (fLineAvailable)
    {
        g_ExtSymbols->GetSourceFileLineOffsets (filename, NULL, 0, &FileLines);
        if (FileLines == 0xFFFFFFFF || FileLines == 0)
            fLineAvailable = FALSE;
    }

    if (fLineAvailable)
    {
        Buffer = new ULONG64[FileLines];
        if (Buffer == NULL)
            fLineAvailable = FALSE;
    }
    
    if (!fLineAvailable)
    {
        vIP = TO_CDADDR(IP);
        // There is no line info.  Just disasm the code.
        while (lcount-- > 0)
        {
            if (IsInterrupt())
                return;
            g_ExtControl->Disassemble (vIP, 0, line, 256, NULL, &vIP);
            ExtOut (line);
        }
        return;
    }

    g_ExtSymbols->GetSourceFileLineOffsets (filename, Buffer, FileLines, NULL);
    
    int beginLine = 0;
    int endLine = 0;
    int lastLine;
    linenum --;
    for (lastLine = linenum; lastLine >= 0; lastLine --) {
        if (IsInterrupt())
            return;
        if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
            g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement);
            if (Displacement == 0) {
                beginLine = lastLine;
                break;
            }
        }
    }
    if (lastLine < 0) {
        int n = lcount / 2;
        lastLine = linenum-1;
        beginLine = lastLine;
        while (lastLine >= 0) {
            if (IsInterrupt())
                return;
            if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
                beginLine = lastLine;
                n --;
                if (n == 0) {
                    break;
                }
            }
            lastLine --;
        }
    }
    while (beginLine > 0 && Buffer[beginLine-1] == DEBUG_INVALID_OFFSET) {
        if (IsInterrupt())
            return;
        beginLine --;
    }
    int endOfFunc = 0;
    for (lastLine = linenum+1; (ULONG)lastLine < FileLines; lastLine ++) {
        if (IsInterrupt())
            return;
        if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
            g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement);
            if (Displacement == 0) {
                endLine = lastLine;
                break;
            }
            endOfFunc = lastLine;
        }
    }
    if ((ULONG)lastLine == FileLines) {
        int n = lcount / 2;
        lastLine = linenum+1;
        endLine = lastLine;
        while ((ULONG)lastLine < FileLines) {
            if (IsInterrupt())
                return;
            if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
                endLine = lastLine;
                n --;
                if (n == 0) {
                    break;
                }
            }
            lastLine ++;
        }
    }

    PVOID MappedBase = NULL;
    ULONG MappedSize = 0;

    class ToUnmap
    {
        PVOID *m_Base;
    public:
        ToUnmap (PVOID *base)
        :m_Base(base)
        {}
        ~ToUnmap ()
        {
            if (*m_Base) {
                UnmapViewOfFile (*m_Base);
                *m_Base = NULL;
            }
        }
    };
    ToUnmap toUnmap(&MappedBase);

#define MAX_SOURCE_PATH 1024
    char Found[MAX_SOURCE_PATH];
    char *pFile;
    if (g_ExtSymbols->FindSourceFile(0, filename,
                       DEBUG_FIND_SOURCE_BEST_MATCH |
                       DEBUG_FIND_SOURCE_FULL_PATH,
                       NULL, Found, sizeof(Found), NULL) != S_OK)
    {
        pFile = filename;
    }
    else
    {
        MappedBase = GenOpenMapping ( Found, &MappedSize );
        pFile = Found;
    }
    
    lastLine = beginLine;
    char *pFileCh = (char*)MappedBase;
    if (MappedBase) {
        ExtOut ("%s\n", pFile);
        int n = beginLine;
        while (n > 0) {
            while (!(pFileCh[0] == '\r' && pFileCh[1] == 0xa)) {
                if (IsInterrupt())
                    return;
                pFileCh ++;
            }
            pFileCh += 2;
            n --;
        }
    }
    
    char filename1[MAX_PATH_FNAME+1];
    for (lastLine = beginLine; lastLine < endLine; lastLine ++) {
        if (IsInterrupt())
            return;
        if (MappedBase) {
            ExtOut ("%4d ", lastLine+1);
            pFileCh = PrintOneLine (pFileCh, (char*)MappedBase+MappedSize);
        }
        if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
            if (MappedBase == 0) {
                ExtOut (">>> %s:%d\n", pFile, lastLine+1);
            }
            vIP = Buffer[lastLine];
            ULONG64 vNextLineIP;
            int i;
            for (i = lastLine + 1; (ULONG)i < FileLines && Buffer[i] == DEBUG_INVALID_OFFSET; i ++) {
                if (IsInterrupt())
                    return;
            }
            if ((ULONG)i == FileLines) {
                vNextLineIP = 0;
            }
            else
                vNextLineIP = Buffer[i];
            while (1) {
                if (IsInterrupt())
                    return;
                g_ExtControl->Disassemble (vIP, 0, line, 256, NULL, &vIP);
                ExtOut (line);
                if (vIP > vNextLineIP || vNextLineIP - vIP > 40) {
                    if (FAILED (g_ExtSymbols->GetLineByOffset (vIP, &linenum,
                                                               filename1,
                                                               MAX_PATH_FNAME+1,
                                                               NULL,
                                                               &Displacement))) {
                        if (lastLine != endOfFunc) {
                            break;
                        }
                        if (strstr (line, "ret") || strstr (line, "jmp")) {
                            break;
                        }
                    }

                    if (linenum != (ULONG)lastLine+1 || strcmp (filename, filename1)) {
                        break;
                    }
                }
                else if (vIP == vNextLineIP) {
                    break;
                }
            }
        }
    }
        
}
コード例 #7
0
ファイル: exts.cpp プロジェクト: 0-wiz-0/coreclr
HRESULT
CALLBACK
DebugExtensionInitialize(PULONG Version, PULONG Flags)
{
    IDebugClient *DebugClient;
    PDEBUG_CONTROL DebugControl;
    HRESULT Hr;

    *Version = DEBUG_EXTENSION_VERSION(1, 0);
    *Flags = 0;

    if (g_Initialized)
    {
        return S_OK;
    }
    g_Initialized = true;

    if ((Hr = DebugCreate(__uuidof(IDebugClient),
                          (void **)&DebugClient)) != S_OK)
    {
        return Hr;
    }
    if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
                                              (void **)&DebugControl)) != S_OK)
    {
        return Hr;
    }

    ExtensionApis.nSize = sizeof (ExtensionApis);
    if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK)
    {
        return Hr;
    }
    
    // Fixes the "Unable to read dynamic function table entries" error messages by disabling the WinDbg security
    // feature that prevents the loading of unknown out of proc tack walkers.
    DebugControl->Execute(DEBUG_OUTCTL_IGNORE, ".settings set EngineInitialization.VerifyFunctionTableCallbacks=false", 
        DEBUG_EXECUTE_NOT_LOGGED | DEBUG_EXECUTE_NO_REPEAT);

    ExtQuery(DebugClient);
    if (IsMiniDumpFileNODAC())
    {
        ExtOut (
            "----------------------------------------------------------------------------\n"
            "The user dump currently examined is a minidump. Consequently, only a subset\n"
            "of sos.dll functionality will be available. If needed, attaching to the live\n"
            "process or debugging a full dump will allow access to sos.dll's full feature\n"
            "set.\n"
            "To create a full user dump use the command: .dump /ma <filename>\n"
            "----------------------------------------------------------------------------\n");
    }
    ExtRelease();
    
    OnUnloadTask::Register(CleanupEventCallbacks);
    g_pCallbacksClient = DebugClient;
    EventCallbacks* pCallbacksObj = new EventCallbacks(DebugClient);
    IDebugEventCallbacks* pCallbacks = NULL;
    pCallbacksObj->QueryInterface(__uuidof(IDebugEventCallbacks), (void**)&pCallbacks);
    pCallbacksObj->Release();

    if(FAILED(Hr = g_pCallbacksClient->SetEventCallbacks(pCallbacks)))
    {
        ExtOut ("SOS: Failed to register callback events\n");
        pCallbacks->Release();
        return Hr;
    }
    pCallbacks->Release();

#ifndef _ARM_
    // Make sure we do not tear down the debugger when a security function fails
    // Since we link statically against CRT this will only affect the SOS module.
    _set_invalid_parameter_handler(_SOS_invalid_parameter);
#endif
    
    DebugControl->Release();
    return S_OK;
}
コード例 #8
0
ファイル: dbgcb.cpp プロジェクト: BwRy/ioctlfuzzer
//--------------------------------------------------------------------------------------
VOID WDBGAPI WinDbgExtensionDllInit(
    PWINDBG_EXTENSION_APIS lpExtensionApis, 
    USHORT usMajorVersion, USHORT usMinorVersion)
{
    if (g_RefCount > 0)
    {
        // extension is allready initialized
        return;
    }

    HRESULT Hr = DebugCreate(__uuidof(IDebugClient), (void **)&g_Client);
    if (Hr != S_OK)
    {
        MessageBoxA(0, "DebugCreate() fails", __FUNCTION__, MB_ICONERROR);
        return;
    }

    Hr = g_Client->QueryInterface(__uuidof(IDebugControl), (void **)&g_Control);
    if (Hr != S_OK)
    {    
        MessageBoxA(
            0, 
            "DebugClient::QueryInterface(IDebugControl) fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    ULONG TargetMachine = 0;
    Hr = g_Control->GetActualProcessorType(&TargetMachine);
    if (Hr == S_OK)
    {                                                     
        switch (TargetMachine)
        {
        case IMAGE_FILE_MACHINE_I386:
            
            g_bIs64 = FALSE;
            g_RegPtrType = DEBUG_VALUE_INT32;
            break;


        case IMAGE_FILE_MACHINE_AMD64:

            g_bIs64 = TRUE;
            g_RegPtrType = DEBUG_VALUE_INT64;
            break;

        default:

            MessageBoxA(
                0, 
                "Target architecture is not supported", 
                __FUNCTION__, MB_ICONERROR
            );

            ExitProcess(0);

            break;
        }
    }
    else
    {
        MessageBoxA(
            0, 
            "DebugControl::GetActualProcessorType() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    Hr = g_Client->QueryInterface(__uuidof(IDebugSymbols3), (void **)&g_Symbols);
    if (Hr != S_OK)
    {    
        MessageBoxA(
            0, 
            "DebugClient::QueryInterface(IDebugSymbols3) fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    Hr = g_Client->QueryInterface(__uuidof(IDebugSystemObjects), (void **)&g_SystemObjects);
    if (Hr != S_OK)
    {    
        MessageBoxA(
            0, 
            "DebugClient::QueryInterface(IDebugSystemObjects) fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    Hr = g_Client->QueryInterface(__uuidof(IDebugRegisters), (void **)&g_Registers);
    if (Hr != S_OK)
    {    
        MessageBoxA(
            0, 
            "DebugClient::QueryInterface(IDebugRegisters) fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    Hr = g_Client->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&g_DataSpaces);
    if (Hr != S_OK)
    {    
        MessageBoxA(
            0, 
            "DebugClient::QueryInterface(IDebugDataSpaces) fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    char *lpszEip = "eip", *lpszEax = "eax", *lpszEcx = "ecx";
    if (g_bIs64)
    {
        // use 64-bit registers for parameter and return value
        lpszEip = "rip";
        lpszEax = "rax";
        lpszEcx = "rcx";
    }

    // Find the register index for eip/rip
    Hr = g_Registers->GetIndexByName(lpszEip, &g_EipIndex);
    if (Hr != S_OK)
    {
        MessageBoxA(
            0, 
            "DebugRegisters::GetIndexByName() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }    

    // Find the register index for eax/rax
    Hr = g_Registers->GetIndexByName(lpszEax, &g_EaxIndex);
    if (Hr != S_OK)
    {
        MessageBoxA(
            0, 
            "DebugRegisters::GetIndexByName() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }    

    // Find the register index for ecx/rcx
    Hr = g_Registers->GetIndexByName(lpszEcx, &g_EcxIndex);
    if (Hr != S_OK)
    {
        MessageBoxA(
            0, 
            "DebugRegisters::GetIndexByName() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    // Find the register index for edx
    Hr = g_Registers->GetIndexByName("edx", &g_EdxIndex);
    if (Hr != S_OK)
    {
        MessageBoxA(
            0, 
            "DebugRegisters::GetIndexByName() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    // Register our event callbacks.
    Hr = g_Client->SetEventCallbacks(&g_EventCb);
    if (Hr != S_OK)
    {
        MessageBoxA(
            0, 
            "DebugClient::SetEventCallbacks() fails", 
            __FUNCTION__, MB_ICONERROR
        );

        ExitProcess(0);
    }

    ExtOut("<col fg=\"srckw\">" __FUNCTION__"(): Initialized (x64: %s)</col>\n", g_bIs64 ? "Yes" : "No");
}
コード例 #9
0
ファイル: dbgcb.cpp プロジェクト: BwRy/ioctlfuzzer
STDMETHODIMP
EventCallbacks::Exception(
    THIS_
    IN PEXCEPTION_RECORD64 Exception,
    IN ULONG FirstChance)
{    
    g_ResumeState = FALSE;

    if (Exception->ExceptionCode == STATUS_BREAKPOINT)
    {
        if (FirstChance)
        {
            DEBUG_VALUE Reg, Ecx, Edx;            

            // Query EIP, EAX and ECX value.
            if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK &&
                g_Registers->GetValue(g_EdxIndex, &Edx) == S_OK &&
                g_Registers->GetValue(g_EcxIndex, &Ecx) == S_OK)
            {
                char szParam[MAX_PATH];
                ULONG ReadedBytes = 0;

                // Read current instruction opcode value.
                ZeroMemory(szParam, sizeof(szParam));
                HRESULT Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Reg), &szParam, 1, &ReadedBytes);                
                if (Hr != S_OK)
                {
                    ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr);
                    return DEBUG_STATUS_NO_CHANGE;
                }

                // Check for int 3 at EIP.
                if (szParam[0] != '\xCC')
                {
                    return DEBUG_STATUS_NO_CHANGE;
                }

                // Check for the magic engine constnat in EDX.
                if (Edx.I32 != DBGCB_GET_SYMBOL &&
                    Edx.I32 != DBGCB_EXECUTE &&
                    Edx.I32 != DBGCB_FIELD_OFFSET)
                {
                    return DEBUG_STATUS_NO_CHANGE;
                }
                
                g_ResumeState = TRUE;                

                // Read ASCII string with command arguments.
                ZeroMemory(szParam, sizeof(szParam));
                Hr = g_DataSpaces->ReadVirtual(RegPtrGet(&Ecx), &szParam, sizeof(szParam), &ReadedBytes);
                if (Hr != S_OK)
                {
                    ExtErr(__FUNCTION__"() ERROR: IDebugDataSpaces::ReadVirtual() fails: %lx\n", Hr);
                    return DEBUG_STATUS_NO_CHANGE;
                }

                switch (Edx.I32)
                {
                case DBGCB_GET_SYMBOL:
                    {
                        ExtOut("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_GET_SYMBOL \"%s\"</col>\n", szParam);

                        RegPtrSet(&Reg, 0);
                        g_Registers->SetValue(g_EaxIndex, &Reg);

                        Hr = g_Control->Evaluate(szParam, g_RegPtrType, &Reg, NULL);
                        if (Hr == S_OK)
                        {
                            // Return symbol address in EAX.
                            g_Registers->SetValue(g_EaxIndex, &Reg);
                        }
                        else
                        {
                            ExtErr(__FUNCTION__"() WARNING: IDebugControl::Evaluate() fails: %lx\n", Hr);
                        }

                        break;
                    }                                 

                case DBGCB_EXECUTE:
                    {
                        ExtOut("<col fg=\"srccmnt\">" __FUNCTION__ "(): DBGCB_EXECUTE</col>\n");

                        // execute debugger command
                        Hr = g_Control->Execute(
                            DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_AMBIENT_DML, 
                            szParam, 
                            DEBUG_EXECUTE_DEFAULT
                        );
                        if (Hr == S_OK)
                        {
                            // Return TRUE in EAX
                            RegPtrSet(&Reg, 1);
                            g_Registers->SetValue(g_EaxIndex, &Reg);
                        }
                        else
                        {
                            ExtErr(__FUNCTION__"() WARNING: IDebugControl::Execute() fails: %lx\n", Hr);
                        }

                        break;
                    }                    

                case DBGCB_FIELD_OFFSET:
                    {
                        RegPtrSet(&Reg, (ULONG64)-1);

                        char *lpszModule = szParam, *lpszStruct = NULL, *lpszField = NULL;

                        ExtOut("<col fg=\"srccmnt\">" __FUNCTION__"(): DBGCB_FIELD_OFFSET \"%s\"</col>\n", szParam);

                        // parse structure and field description string
                        if (lpszStruct = strstr(lpszModule, "!"))
                        {
                            *lpszStruct = '\x00';
                            lpszStruct += 1;

                            if (lpszField = strstr(lpszStruct, "::"))
                            {
                                *lpszField = '\x00';
                                lpszField += 2;
                            }
                        }                        

                        if (lpszStruct && lpszField)
                        {
                            // enumerate fields
                            for (ULONG i = 0; ;i++) 
                            {   
                                ULONG64 Module = 0;
                                ULONG TypeId = 0;    

                                // get ID of this symbol
                                Hr = g_Symbols->GetSymbolTypeId(lpszStruct, &TypeId, &Module);
                                if (Hr == S_OK) 
                                {
                                    char szFieldName[MAX_PATH];

                                    // query name of the filed
                                    HRESULT Hr = g_Symbols->GetFieldName(Module, TypeId, i, szFieldName, MAX_PATH, NULL);
                                    if (Hr == S_OK) 
                                    {
                                        ULONG Offset = 0, FieldTypeId = 0;

                                        // query filed type and offset
                                        Hr = g_Symbols->GetFieldTypeAndOffset(Module, TypeId, szFieldName, &FieldTypeId, &Offset);                                   
                                        if (Hr == S_OK)
                                        {
                                            if (!strcmp(szFieldName, lpszField))
                                            {
                                                // Return symbol offset in EAX
                                                RegPtrSet(&Reg, (ULONG64)Offset);                                                
                                                break;
                                            }
                                        }            
                                        else 
                                        {
                                            ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldTypeAndOffset() fails: %lx\n", Hr);
                                        }
                                    } 
                                    else if (Hr == E_INVALIDARG) 
                                    {
                                        // All Fields done
                                        break;
                                    } 
                                    else 
                                    {
                                        ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetFieldName() fails: %lx\n", Hr);
                                    }
                                }
                                else
                                {
                                    ExtErr(__FUNCTION__"() WARNING: IDebugSymbols3::GetSymbolTypeId() fails: %lx\n", Hr);
                                }                                
                            }
                        }
                        else
                        {
                            ExtErr(__FUNCTION__"() WARNING: Bad name format (must be <module>!<struct_name>::<field_name>)\n");
                        }

                        g_Registers->SetValue(g_EaxIndex, &Reg);

                        break;
                    }                    

                default:

                    return DEBUG_STATUS_NO_CHANGE;
                }

                // Skip current int 3 instruction and continue execution
                if (g_Registers->GetValue(g_EipIndex, &Reg) == S_OK && Reg.Type == DEBUG_VALUE_INT32)
                {
                    if (g_bIs64)
                    {
                        Reg.I64 += 1;
                    }
                    else
                    {
                        Reg.I32 += 1;
                    }

                    g_Registers->SetValue(g_EipIndex, &Reg);                    
                }                 

                return DEBUG_STATUS_GO_HANDLED;
            }                      
        }
    }    

    return DEBUG_STATUS_NO_CHANGE;
}