Dia2dump.cpp Source File

The following Dia2dump.cpp source code displays the contents of a .pdb file. This source code is used by Dia2dump Sample.

// dia2dump.cpp : Dump contents of a pdb file using DIA.
//
//       Copyright (c) Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------
//

#include "stdafx.h"
#include "diacreate.h"
#include "cvconst.h"

void Fatal( const char *msg )
{
    printf( msg );
    printf( "\n" );
    exit(-1);
}

void Error( const char *msg )
{
    printf( " **error: %s\n", msg );
}

class CDiaBSTR 
{
    BSTR m_bstr;
public:
    CDiaBSTR()         { m_bstr = NULL; }
    ~CDiaBSTR()        { if (m_bstr != NULL) SysFreeString( m_bstr ); }
    BSTR *operator &() { assert(m_bstr == NULL); return &m_bstr; }
    operator BSTR()    { assert(m_bstr != NULL); return m_bstr; }
};


CComPtr<IDiaSession> psession;
CComPtr<IDiaSymbol> pglobal;

void printVariant( VARIANT& v )
{
    switch( v.vt )
    {
 //*    LONGLONG       VT_I8
    case VT_I8:
        printf( "%ld", v.llVal );
        break;
 //*    LONG           VT_I4
    case VT_I4:
        printf( "%d", v.lVal );
        break;
 //*    BYTE           VT_UI1
    case VT_UI1:
        printf( "%d", v.bVal);
        break;
 //*    SHORT          VT_I2
    case VT_I2:
        printf( "%d", v.iVal);
        break;
 //*    CHAR           VT_I1
    case VT_I1:
        printf( "%d", v.cVal);
        break;
 //*    USHORT         VT_UI2
    case VT_UI2:
        printf( "%d", v.uiVal);
        break;
//*    ULONG          VT_UI4
    case VT_UI4:
        printf( "%d", v.ulVal);
        break;
 //*    ULONGLONG      VT_UI8
    case VT_UI8:
        printf( "%ld", v.ullVal);
        break;
 //*    INT            VT_INT
    case VT_INT:
        printf( "%d", v.intVal);
        break;
 //*    UINT           VT_UINT
    case VT_UINT:
        printf( "%d", v.uintVal);
        break;
    default:
        printf( "<Not implemented>" );
        break;
    }
}

void printBound( IDiaSymbol* pBound )
{
    DWORD tag = 0;
    CDiaBSTR name;
    DWORD kind;
    pBound->get_symTag( &tag );
    pBound->get_locationType( &kind );
    if ( tag == SymTagData && kind == LocIsConstant ) {
        CComVariant v;
        pBound->get_value( &v );
        printVariant( v );
    } else if ( pBound->get_name( &name ) == S_OK ) {
        printf( "%ws", name );
    }
}

void printType( IDiaSymbol* pType )
{
    DWORD tag = 0;
    pType->get_symTag( &tag );
    CDiaBSTR name;
    if ( pType->get_name( &name ) == S_OK && name != NULL ) {
        printf( "-%ws", name );
    } else if ( tag == SymTagPointerType ) {
        CComPtr<IDiaSymbol> pBaseType;
        if (  pType->get_type( &pBaseType ) == S_OK ) {
            printType( pBaseType );
            printf( "*" );
        } else {
            Fatal( "pointer get_type" );
        }
    } else if ( tag == SymTagBaseType ) {
        ULONGLONG size;
        DWORD bt;
        if ( pType->get_length( &size ) != S_OK )
            Fatal( "Internal error, no Length" );
        if ( pType->get_baseType( &bt ) != S_OK )
            Fatal( "Internal error, no baseType" );
         wprintf( L"(base type=%d, len=%ld)  ", bt, size );
    } else if ( tag == SymTagArrayType ) {
        CComPtr<IDiaSymbol> pBaseType;
        if ( pType->get_type( &pBaseType ) == S_OK ) {
            printType( pBaseType );
        } else {
            Fatal( "array get_type" );
        }
        DWORD rank;
        DWORD celt;
        LONG count;
        CComPtr< IDiaEnumSymbols > pEnum;
        if ( pType->get_rank( &rank ) == S_OK ) {
            if ( pType->findChildren( SymTagDimension, NULL, nsNone, &pEnum ) == S_OK && pEnum != NULL ) {
                CComPtr< IDiaSymbol > pSym;
                while ( pEnum->Next( 1, &pSym, &celt ) == S_OK && celt == 1 ) {
                    CComPtr< IDiaSymbol > pBound;
                    printf( "[" );
                    if ( pSym->get_lowerBound( &pBound ) == S_OK ) {
                        printBound( pBound );
                        printf("..");
                    }
                    pBound = NULL;
                    if ( pSym->get_upperBound( &pBound ) == S_OK ) {
                        printBound( pBound );
                    }
                    pBound = NULL;
                    printf( "]" );
                    pSym = NULL;

                }
            } 
        } else if ( pType->findChildren( SymTagCustomType, NULL, nsNone, &pEnum ) == S_OK && pEnum != NULL && SUCCEEDED( pEnum->get_Count( &count ) ) && count > 0 ){
                CComPtr< IDiaSymbol > pSym;
                while ( pEnum->Next( 1, &pSym, &celt ) == S_OK && celt == 1 ) {
                    printf( "[" );
                    printType( pSym );
                    printf( "]" );
                    pSym = NULL;
                }
        } else {
            ULONGLONG lenArray;
            ULONGLONG lenElem;
            if ( pType->get_length( &lenArray ) != S_OK
                || pBaseType->get_length( &lenElem ) != S_OK ) {
                Fatal( "No type length." );
            }
            printf( "[%ld]", lenArray/lenElem );
        }
    } else if ( tag == SymTagFunctionType ) {
        printf( "Function Type" );
    } else if ( tag == SymTagCustomType ) {
        printf( "Custom Type: " );
        DWORD id;
        DWORD rec;
        GUID guid;
        if ( pType->get_guid( &guid ) == S_OK ) {
            wchar_t wszGuid[64];
            StringFromGUID2(guid, wszGuid, 64);
            printf( "%ws", wszGuid );
        } else if ( pType->get_oemId( &id ) == S_OK && pType->get_oemSymbolId( &rec ) == S_OK ) {
            printf( "%x:%x", id, rec );
        }
        DWORD len = 0;
        if ( pType->get_types( 0, &len, NULL ) == S_OK && len > 0 ) {
            IDiaSymbol** psyms = new IDiaSymbol*[ len ];
            if ( psyms == NULL ) {
                Fatal( "out of memory" );
            }
            pType->get_types( len, &len, psyms );
            for ( DWORD i = 0; i < len; ++i ) {
                printf( " <" );
                printType( psyms[i] );
                printf( ">" );
                psyms[i]->Release();
            }
            delete [] psyms;
        }
        len = 0;
        if ( pType->get_dataBytes( 0, &len, NULL ) == S_OK && len > 0 ) {
            BYTE* pdata = new BYTE[ len ];
            if ( pdata == NULL ) {
                Fatal( "out of memory" );
            }
            pType->get_dataBytes( len, &len, pdata );
            printf( "<data" );
            for ( DWORD i = 0; i < len; ++i ) {
                printf( " %02x", pdata[i] );
            }
            printf( " data>" );
            delete [] pdata;
        }
    } else {
        printf( "No Type.");
    }
}

void dumpFunctionLines( IDiaSymbol* pSymbol, IDiaSession* pSession )
{
    ULONGLONG length = 0;
    DWORD isect = 0;
    DWORD offset = 0;
    pSymbol->get_addressSection( &isect );
    pSymbol->get_addressOffset( &offset );
    pSymbol->get_length( &length );
    if ( isect != 0 && length > 0 ) {
        CComPtr< IDiaEnumLineNumbers > pLines;
        if ( SUCCEEDED( pSession->findLinesByAddr( isect, offset, static_cast<DWORD>( length ), &pLines ) ) ) {
            CComPtr< IDiaLineNumber > pLine;
            DWORD celt;
            bool firstLine = true;
            while ( SUCCEEDED( pLines->Next( 1, &pLine, &celt ) ) && celt == 1 ){
                DWORD offset;
                DWORD seg;
                DWORD linenum;
                CComPtr< IDiaSymbol > pComp;
                CComPtr< IDiaSourceFile > pSrc;
                pLine->get_compiland( &pComp );
                pLine->get_sourceFile( &pSrc );
                pLine->get_addressSection( &seg );
                pLine->get_addressOffset( &offset );
                pLine->get_lineNumber( &linenum );
                printf( "\tline %d at 0x%x:0x%x\n", linenum, seg, offset );
                pLine = NULL;
                if ( firstLine ) {
                    // sanity check
                    CComPtr< IDiaEnumLineNumbers > pLinesByLineNum;
                    if ( SUCCEEDED( pSession->findLinesByLinenum( pComp, pSrc, linenum, 0, &pLinesByLineNum ) ) ) {
                        CComPtr< IDiaLineNumber > pLine;
                        DWORD celt;
                        while ( SUCCEEDED( pLinesByLineNum->Next( 1, &pLine, &celt ) ) && celt == 1 ){
                            DWORD offset;
                            DWORD seg;
                            DWORD linenum;
                            pLine->get_addressSection( &seg );
                            pLine->get_addressOffset( &offset );
                            pLine->get_lineNumber( &linenum );
                            printf( "\t\tfound line %d at 0x%x:0x%x\n", linenum, seg, offset );
                            pLine = NULL;
                       }
                    }
                    firstLine = false;
                }
            }
        }
    }
}

wchar_t* szTags[] = {
    L"",
    L"Executable (Global)",
    L"Compiland", 
    L"CompilandDetails", 
    L"CompilandEnv",
    L"Function", 
    L"Block",
    L"Data",
    L"Unused", 
    L"Label", 
    L"PublicSymbol", 
    L"UDT", 
    L"Enum", 
    L"FunctionType", 
    L"PointerType", 
    L"ArrayType", 
    L"BaseType", 
    L"Typedef", 
    L"BaseClass",
    L"Friend",
    L"FunctionArgType", 
    L"FuncDebugStart", 
    L"FuncDebugEnd",
    L"UsingNamespace", 
    L"VTableShape",
    L"VTable",
    L"Custom",
    L"Thunk",
    L"CustomType",
    L""
};

bool fTagScopes[] = {
    false,
    true,
    true, 
    false, 
    false,
    true, 
    true,
    false,
    false, 
    false, 
    false, 
    false, 
    false, 
    false, 
    false, 
    false, 
    false, 
    false, 
    false,
    false,
    false, 
    false, 
    false,
    false, 
    false,
    false,
    false,
    false,
    false,
    false
};

wchar_t* szDataKinds[] = {
    L"Unknown",
    L"Local",
    L"Static Local",
    L"Parameter",
    L"Object Pointer",
    L"File Static",
    L"Global",
    L"Member",
    L"Static Member",
    L"Constant"
};

wchar_t* symbolTagName( DWORD tag )
{
    if ( tag > SymTagNull && tag < SymTagMax )
        return szTags[ tag ];
    assert( false );
    return L"Error!";
}

bool isScopeSym( DWORD tag )
{
    if ( tag > SymTagNull && tag < SymTagMax )
        return fTagScopes[ tag ];
    assert( false );
    return false;
}

void printScopeName( IDiaSymbol* pscope )
{
    DWORD tag;
    CDiaBSTR name;
    if ( pscope->get_symTag( &tag ) != S_OK )
        Fatal( "Internal error, getting SymTag" );
    if ( pscope->get_name( &name ) != S_OK )
        Fatal( "Internal error, getting name" );
    if ( name == NULL ) {
        wprintf( szTags[ tag ] );
        return;
    }
    wprintf( L"%ws (%ws)", name, szTags[ tag ] );
}

void PrintNameFromScope( wchar_t* name, IDiaSymbol* pscope, IDiaEnumSymbols* pEnum )
{
    CComPtr< IDiaSymbol> pSym;
    DWORD celt;
    while ( SUCCEEDED( pEnum->Next( 1, &pSym, &celt ) ) && celt == 1 ) {
        DWORD tag;
        CDiaBSTR name;
        if ( pSym->get_symTag( &tag ) != S_OK )
            Fatal( "Internal error, no SymTag" );
        if ( pSym->get_name( &name ) != S_OK )
            Fatal( "Internal error, no name" );
        // tagtype name found in name or scopeTag
        wprintf( L"\t%ws %ws found in ", szTags[ tag ], name );
        printScopeName( pscope );
        wprintf( L"\n" );
        pSym = 0;
    }
}

void FindNameInNamespace( wchar_t* name, IDiaSymbol* pnamespace )
{
    wchar_t *buf = NULL;
    CDiaBSTR szNamespace;
    pnamespace->get_name( &szNamespace );
    buf = new wchar_t[ wcslen( name ) + wcslen( szNamespace ) + 3];
    if ( buf == NULL ) {
        Fatal( "out of memory" );
    }
    wsprintfW( buf, L"%s::%s", szNamespace, name );
    CComPtr< IDiaEnumSymbols > pEnum;
    if ( FAILED( pglobal->findChildren( SymTagNull, name, nsCaseSensitive, &pEnum ) ) )
        Fatal( "Namespace findChildren failed" );
    long cnt = 0;
    if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a name!
        PrintNameFromScope( name, pglobal, pEnum );
    }
    delete [] buf;
}

void FindNameInEnum( wchar_t* name, IDiaSymbol* penumeration )
{
    CComPtr< IDiaEnumSymbols > pEnum;
    if ( FAILED( penumeration->findChildren( SymTagData, name, nsRegularExpression, &pEnum ) ) )
        Fatal( "Enumeration findChildren failed" );
    long cnt = 0;
    if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a name!
        PrintNameFromScope( name, penumeration, pEnum );
    }
}

void FindNameInClass( wchar_t* name, IDiaSymbol* pclass )
{
    CComPtr< IDiaEnumSymbols > pEnum;
    if ( FAILED( pclass->findChildren( SymTagNull, name, nsCaseSensitive, &pEnum ) ) ) 
        Fatal( "Class findChildren failed" );
    long cnt = 0;
    if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a name!
        PrintNameFromScope( name, pclass, pEnum );
    }
    pEnum = 0;
    // check out the enumerations
    CComPtr< IDiaSymbol > pSym;
    if ( FAILED( pclass->findChildren( SymTagEnum, NULL, nsNone, &pEnum ) ) ) 
        Fatal( "Class findChildren for enums failed" );
    if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found an enum!
        DWORD celt;
        while ( SUCCEEDED( pEnum->Next( 1, &pSym, &celt ) ) && celt == 1 ) {
            FindNameInEnum( name, pSym );
            pSym = 0;
        }
    }
    pEnum = 0;
    // check out the base classes
    if ( FAILED( pclass->findChildren( SymTagBaseClass, NULL, nsNone, &pEnum ) ) ) 
        Fatal( "Class findChildren for base classes failed" );
    if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a base class!
        DWORD celt;
        while ( SUCCEEDED( pEnum->Next( 1, &pSym, &celt ) ) && celt == 1 ) {
            CComPtr< IDiaSymbol > pClass;
            if (  pSym->get_type( &pClass ) == S_OK )
                Fatal( "Getting class for a base type failed" );
            if ( pClass )
                FindNameInClass( name, pClass );
            pSym = 0;
        }
    }
}

void FindCppNameInScope( wchar_t* name, IDiaSymbol* pScope )
{
    // while ( scope ) {
        // Scan the scope for a symbol.
        // If any namespaces, then scan for name in namespace.
        // If scope is a member function then 
        //    scan class parent for member with name.
        // scope = scope.parent;
    // }

    wprintf( L"Finding name \"%ws\" in ", name );
    printScopeName( pScope );
    wprintf( L"\n" );

    DWORD celt;
    long cnt = 0;
    CComPtr< IDiaSymbol > pSym;
    CComPtr< IDiaSymbol > pParent;
    CComPtr< IDiaSymbol > pscope;
    for ( pscope = pScope; pscope != NULL; ) {
        CComPtr< IDiaEnumSymbols > pEnum;
        // local data search
        if ( FAILED( pscope->findChildren( SymTagNull, name, nsCaseSensitive, &pEnum ) ) )
            Fatal( "Local scope findChildren failed" );
        if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a name!
            PrintNameFromScope( name, pscope, pEnum );
        }
        pEnum = 0;
        // look into any namespaces
        if ( FAILED( pscope->findChildren( SymTagUsingNamespace, NULL, nsNone, &pEnum ) ) )
            Fatal( "Namespace findChildren failed" );
        if ( pEnum != NULL && SUCCEEDED( pEnum->get_Count(&cnt) ) && cnt > 0 ) {  // found a namespace!
            while ( SUCCEEDED( pEnum->Next( 1, &pSym, &celt ) ) && celt == 1 ) {
                FindNameInNamespace( name, pSym );
                pSym = 0;
            }
        }
        pEnum = 0;
        // is this a member function?
        DWORD tag = SymTagNull;
        if ( SUCCEEDED( pscope->get_symTag( &tag ) ) 
            && tag == SymTagFunction
            && SUCCEEDED( pscope->get_classParent( &pParent ) )
            && pParent != NULL ) {
            FindNameInClass( name, pParent );
        }
        pParent = NULL;
        // move to lexical parent
        if ( SUCCEEDED( pscope->get_lexicalParent( &pParent ) )
            && pParent != NULL ) {
            pscope = pParent;
        } else {
            pscope = NULL;
        }
        pParent = NULL;
    };
}

void dumpLocalVars( DWORD rva )
{
    CComPtr< IDiaSymbol > pBlock;
    if ( FAILED( psession->findSymbolByRVA( rva, SymTagBlock, &pBlock ) ) ) {
        Fatal( "Failed to find symbols by RVA" );
    }
    CComPtr< IDiaSymbol > pscope;
    for ( ; pBlock != NULL; ) {
        CComPtr< IDiaEnumSymbols > pEnum;
        // local data search
        if ( FAILED( pBlock->findChildren( SymTagNull, NULL, nsNone, &pEnum ) ) )
            Fatal( "Local scope findChildren failed" );
        CComPtr< IDiaSymbol > pSymbol;
        DWORD tag;
        DWORD celt;
        while ( pEnum != NULL && SUCCEEDED( pEnum->Next( 1, &pSymbol, &celt ) ) && celt == 1 ) {
            pSymbol->get_symTag( &tag );
            if ( tag == SymTagData ) {
                CDiaBSTR name;
                DWORD kind;
                pSymbol->get_name( &name );
                pSymbol->get_dataKind( &kind );
                if ( name != NULL )
                    wprintf( L"\t%s (%s)\n", name, szDataKinds[ kind ] );
            } else if ( tag == SymTagAnnotation ) {
                CComPtr< IDiaEnumSymbols > pValues;
                // local data search
                wprintf( L"\tAnnotation:\n" );
                if ( FAILED( pSymbol->findChildren( SymTagNull, NULL, nsNone, &pValues ) ) )
                    Fatal( "Annotation findChildren failed" );
                pSymbol = NULL;
                while ( pValues != NULL && SUCCEEDED( pValues->Next( 1, &pSymbol, &celt ) ) && celt == 1 ) {
                    CComVariant value;
                    if ( pSymbol->get_value( &value ) != S_OK )
                        Fatal( "No value for annotation data." );
                    wprintf( L"\t\t%ws\n", value.bstrVal );
                    pSymbol = NULL;
                }
            }
            pSymbol = NULL;
        }
        pBlock->get_symTag( &tag ); 
        if ( tag == SymTagFunction )    // stop when at function scope
            break;
        // move to lexical parent
        CComPtr< IDiaSymbol > pParent;
        if ( SUCCEEDED( pBlock->get_lexicalParent( &pParent ) )
            && pParent != NULL ) {
            pBlock = pParent;
        } else {
            Fatal( "Finding lexical parent failed." );
        }
    };
}

DWORD PrintNameAddr( IDiaSymbol* pSym )
{
    DWORD rva;
    if ( pSym->get_relativeVirtualAddress( &rva ) != S_OK )
        rva = 0;    // no rva, must be an absolute value
    DWORD tag;
    pSym->get_symTag( &tag );
    CDiaBSTR name;
    if ( pSym->get_name( &name ) != S_OK )
        printf( "\t0x%08X (%ws) <no name>\n", rva, szTags[ tag ] );
    else {
        printf( "\t0x%08X (%ws) %ws\n", rva, szTags[ tag ], name );
    }
    return rva;
}

void        
DumpLex( IDiaSymbol* pscope, int tabs )
{
    HRESULT hr;

    CComPtr<IDiaEnumSymbols> pSymbols;    
    if ( SUCCEEDED( pscope->findChildren( SymTagNull, NULL, nsNone, &pSymbols ) ) ) {
        CComPtr<IDiaSymbol> pSymbol;
        ULONG celt = 0;
        while ( pSymbols != NULL && SUCCEEDED( hr = pSymbols->Next( 1, &pSymbol, &celt ) ) && celt == 1 ) {
            for ( int i = 0; i < tabs; ++i )
                printf( "\t" );
            CDiaBSTR name;
            if ( pSymbol->get_name( &name ) == S_OK && name != NULL ) {
                printf( "%ws", name );
            }
            DWORD symTag;
            pSymbol->get_symTag( &symTag );
            printf( " : %ws\n", szTags[ symTag ] );
            switch ( symTag ) {
            case SymTagExe:
                assert( false );
                break;
            case SymTagCompiland:
            case SymTagFunction:
            case SymTagBlock:
                DumpLex( pSymbol, tabs+1 );
                break;
            default:
                break;
            }
            pSymbol = NULL;
        }
    }
}

void        
Dump(
    char *szFilename,
    IDiaDataSource* pSource,
    wchar_t* szLookup
)
{
    HRESULT hr;
    wchar_t wszFilename[ _MAX_PATH ];
    mbstowcs( wszFilename, szFilename, sizeof( wszFilename )/sizeof( wszFilename[0] ) );
    if ( FAILED( pSource->loadDataFromPdb( wszFilename ) ) ) 
        if ( FAILED( pSource->loadDataForExe( wszFilename, NULL, NULL ) ) ) 
            Fatal( "loadDataFromPdb/Exe" );

    if ( FAILED( pSource->openSession( &psession ) ) ) 
        Fatal( "openSession" );
    if ( FAILED( psession->get_globalScope( &pglobal) ) )
        Fatal( "get_globalScope" );
    DWORD id = 0;
    pglobal->get_symIndexId( &id );
    if ( id == 0 )
        Fatal( "get_indexId" );

    ULONG celt = 0;

    CComPtr<IDiaEnumSymbols> pEnum;
    CComPtr<IDiaSymbol> pSymbol;

    pglobal->findChildren(SymTagUDT,NULL,nsfCaseInsensitive|nsfUndecoratedName,&pEnum);
    while ( SUCCEEDED( hr = pEnum->Next( 1, &pSymbol, &celt ) ) && celt == 1 ) {
        CDiaBSTR name;
        if ( pSymbol->get_name( &name ) != S_OK )
            Fatal( "get_name" );
        printf( "Found UDT: %ws\n", name );
        ULONGLONG len = 0;
        pSymbol->get_length( &len );
        if ( len == 0 ) {
            Error( "could not get length" );
        }
        pSymbol = 0;
    }

    CComPtr<IDiaEnumTables> pTables;
    if ( FAILED( psession->getEnumTables( &pTables ) ) )
        Fatal( "getEnumTables" );
    CComPtr< IDiaTable > pTable;
    while ( SUCCEEDED( hr = pTables->Next( 1, &pTable, &celt ) ) && celt == 1 ) {
        CDiaBSTR bstrTableName;
        if ( pTable->get_name( &bstrTableName ) != 0 )
            Fatal( "get_name" );
        printf( "Found table: %ws\n", bstrTableName );
        CComPtr<IDiaEnumSymbols> pSymbols;
        CComPtr<IDiaEnumSourceFiles> pSourceFiles;
        CComPtr<IDiaEnumSegments> pSegments;
        CComPtr<IDiaEnumSectionContribs> pSecContribs;
        if ( SUCCEEDED( pTable->QueryInterface( _uuidof( IDiaEnumSymbols ), (void**)&pSymbols ) ) ) {
            CComPtr<IDiaSymbol> pSymbol;
            while ( SUCCEEDED( hr = pSymbols->Next( 1, &pSymbol, &celt ) ) && celt == 1 ) {
                DWORD symIndex;
                pSymbol->get_symIndexId( &symIndex );
                DWORD symTag;
                pSymbol->get_symTag( &symTag );
                CDiaBSTR name;
                if ( pSymbol->get_name( &name ) == S_OK && name != NULL ) {
                    printf( "sym name: %ws", name );
                    if ( symTag == SymTagPublicSymbol ) {
                        CDiaBSTR undName;
                        pSymbol->get_undecoratedName( &undName );
                        printf( " (%ws)", undName );
                    }
                    CComPtr<IDiaSymbol> pType;
                    if ( pSymbol->get_type( &pType ) == S_OK ) {
                        printf( " has type " );
                        printType( pType );

                        DWORD id = 0;
                        CComPtr< IDiaSymbol > ptypeSym;
                        pSymbol->get_typeId( &id );
                        if ( FAILED( psession->symbolById( id, &ptypeSym ) ) ||
                            psession->symsAreEquiv( pType, ptypeSym ) != S_OK ) {
                                Fatal( "Sym type equality" );
                        }
                    }
                    printf( "\n" );
                    if ( symTag == SymTagFunction ) {
                        dumpFunctionLines( pSymbol, psession );
                        DWORD loctype;
                        if ( pSymbol->get_locationType( &loctype ) == S_OK && loctype == LocIsStatic ) {
                            DWORD rva;
                            pSymbol->get_relativeVirtualAddress( &rva );
                            if ( rva != 0 ) {
                                dumpLocalVars( rva );

                                CComPtr< IDiaSymbol > pfuncSym;
                                if ( SUCCEEDED( psession->findSymbolByRVA( rva, SymTagNull, &pfuncSym ) ) ) {
                                    if ( psession->symsAreEquiv( pfuncSym, pSymbol ) != S_OK ) {
                                        CDiaBSTR name;
                                        DWORD tag;
                                        pfuncSym->get_symTag( &tag );
                                        pfuncSym->get_name( &name );
                                        printf( "\tfound alt symbol: %ws (%ws)\n", name != NULL ? name : L"", szTags[ tag ] );
                                    }
                                } else {
                                    Fatal( "No function symbol found by rva." );
                                }
                            }
                        }
                    } 
                } 
                if ( isScopeSym( symTag ) && szLookup ) {
                    FindCppNameInScope( szLookup, pSymbol );
                }
                pSymbol = NULL;
            }
        } else if ( SUCCEEDED( pTable->QueryInterface( _uuidof( IDiaEnumSourceFiles ), (void**)&pSourceFiles ) ) ) {
            CComPtr<IDiaSourceFile> pSourceFile;
            while ( SUCCEEDED( hr = pSourceFiles->Next( 1, &pSourceFile, &celt ) ) && celt == 1 ) {
                CDiaBSTR fileName;
                if ( pSourceFile->get_fileName( &fileName) == S_OK ) {
                    printf( "file name: %ws\n", fileName );
                }
                pSourceFile = NULL;
            }
        } else if ( SUCCEEDED( pTable->QueryInterface( _uuidof( IDiaEnumSegments ), (void**)&pSegments ) ) ) {
            CComPtr<IDiaSegment> pSegment;
            while ( SUCCEEDED( hr = pSegments->Next( 1, &pSegment, &celt ) ) && celt == 1 ) {
                DWORD rva;
                DWORD seg;
                pSegment->get_addressSection( &seg );
                if ( pSegment->get_relativeVirtualAddress( &rva ) == S_OK ) {
                    printf( "Segment %i addr: 0x%.8X\n", seg, rva );
                    pSegment = NULL;
                    CComPtr<IDiaSymbol> pSym;
                    if ( psession->findSymbolByRVA( rva, SymTagNull, &pSym ) == S_OK ) {
                        CDiaBSTR name;
                        DWORD tag;
                        pSym->get_symTag( &tag );
                        pSym->get_name( &name );
                        printf( "\tClosest symbol: %ws (%ws)\n", name != NULL ? name : L"", szTags[ tag ] );
                    }
                } else {
                    printf( "Segment %i \n", seg );
                    pSegment = NULL;
                    CComPtr<IDiaSymbol> pSym;
                    if ( SUCCEEDED( psession->findSymbolByAddr( seg, 0, SymTagNull, &pSym ) ) ) {
                        CDiaBSTR name;
                        DWORD tag;
                        pSym->get_symTag( &tag );
                        pSym->get_name( &name );
                        printf( "\tClosest symbol: %ws (%ws)\n", name != NULL ? name : L"", szTags[ tag ] );
                    }
                }
            }
        } else if ( SUCCEEDED( pTable->QueryInterface( _uuidof( IDiaEnumSectionContribs ), (void**)&pSecContribs ) ) ) {
            printf( "SecContribs\n" );
            CComPtr<IDiaSectionContrib> pSecContrib;
            while ( SUCCEEDED( hr = pSecContribs->Next( 1, &pSecContrib, &celt ) ) && celt == 1 ) {
                DWORD rva;
                if ( pSecContrib->get_relativeVirtualAddress( &rva ) == S_OK ) {
                    printf( "\taddr: 0x%.8X", rva );
                    pSecContrib = NULL;
                    CComPtr<IDiaSymbol> pSym;
                    if ( psession->findSymbolByRVA( rva, SymTagNull, &pSym ) == S_OK ) {
                        CDiaBSTR name;
                        DWORD tag;
                        pSym->get_symTag( &tag );
                        pSym->get_name( &name );
                        printf( "     symbol: %ws (%ws)\n", name != NULL ? name : L"", szTags[ tag ] );
                    } else {
                        printf( "<no symbol found?>\n" );
                    }
                } else {
                    DWORD isect;
                    DWORD offset;
                    pSecContrib->get_addressSection( &isect );
                    pSecContrib->get_addressOffset( &offset );
                    printf( "\taddr: 0x%.4X:0x%.8X", isect, offset );
                    pSecContrib = NULL;
                    CComPtr<IDiaSymbol> pSym;
                    if ( SUCCEEDED( psession->findSymbolByAddr( isect, offset, SymTagNull, &pSym ) ) ) {
                        CDiaBSTR name;
                        DWORD tag;
                        pSym->get_symTag( &tag );
                        pSym->get_name( &name );
                        printf( "     symbol: %ws (%ws)\n", name != NULL ? name : L"", szTags[ tag ] );
                    } else {
                        printf( "<no symbol found?>\n" );
                    }            
                }
            }
        }

        pTable = NULL;
    }
    CComPtr<IDiaEnumSymbolsByAddr> pEnumByAddr;
    if ( FAILED( psession->getSymbolsByAddr( &pEnumByAddr ) ) )
        Fatal( "getSymbolsByAddr" );
    CComPtr<IDiaSymbol> pSym;
    if ( FAILED( pEnumByAddr->symbolByAddr( 1, 0, &pSym ) ) )
        Fatal( "symbolByAddr" );
    DWORD rvaLast = 0;
    if ( pSym->get_relativeVirtualAddress( &rvaLast ) == S_OK ) {
        pSym = 0;
        if ( FAILED( pEnumByAddr->symbolByRVA( rvaLast, &pSym ) ) )
            Fatal( "symbolByAddr" );
        printf( "Symbols in order\n" );
        do { 
            rvaLast = PrintNameAddr( pSym );
            pSym = 0;
            celt = 0;
            if ( FAILED( hr = pEnumByAddr->Next( 1, &pSym, &celt ) ) ) 
                break;
        } while ( celt == 1 );

        printf( "Symbols in reverse order\n" );
        pSym = 0;
        if ( FAILED( pEnumByAddr->symbolByRVA( rvaLast, &pSym ) ) )
            Fatal( "symbolByRva" );
        printf( "Symbols in order\n" );
        do { 
            rvaLast = PrintNameAddr( pSym );
            pSym = 0;
            celt = 0;
            if ( FAILED( hr = pEnumByAddr->Prev( 1, &pSym, &celt ) ) ) 
                break;
        } while ( celt == 1 );

        if ( FAILED( hr ) )
            Fatal( "Next" );
    }

}

void usage( int argc, char* argv[] )
{
    printf( "usage: %s <pdb-filename>\n", argv[0] );
    exit( -1 );
}

const char* diaPaths[] = {
        "msdia71.dll",
        "..\\bin\\msdia71.dll",
        "..\\..\\bin\\msdia71.dll",
        0
};

int main(int argc, char* argv[])
{

    if ( argc < 2 ) {
        usage(argc, argv);
    }

    HRESULT hr;
    hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        Fatal("CoInitialize failed\n");
    }

    CComPtr<IDiaDataSource> pSource;
    // Initialize The Component Object Module Library
    // Obtain Access To The Provider
    hr = CoCreateInstance( CLSID_DiaSource, NULL, CLSCTX_INPROC_SERVER, 
        __uuidof( IDiaDataSource ), (void **) &pSource);

    if (FAILED(hr))
    {   
        Fatal("Could not CoCreate CLSID_DiaSource. Register msdia71.dll." );
    }
    if ( argc > 2 ) {
        wchar_t name[ 256 ];
        mbstowcs( name, argv[ 2 ], 256 );
        Dump( argv[ 1 ], pSource, name );
        DumpLex( pglobal, 0 );
    } else {
        Dump( argv[ 1 ], pSource, NULL );
    }

    pglobal  = 0;
    psession = 0;
    pSource  = 0;

    CoUninitialize();
    return 0;
}