Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / MFC

How to Inspect the Content of a Program Database (PDB) File

Rate me:
Please Sign up or sign in to vote.
4.87/5 (64 votes)
14 Jan 2014CPOL4 min read 487.2K   21.8K   244  
Get to know the files you use on a daily basis when debugging your application with Visual Studio or WinDbg.
//	------------------------------------------------------------------------------------------------
//	File name:		PdbFile.cpp
//	Author:			Marc Ochsenmeier
//	Email:			info@winitor.net
//	Web:			www.winitor.net - 
//	Date:			20.08.2011
//
//	------------------------------------------------------------------------------------------------
#include "stdafx.h"

#include "PdbTranslationMaps.h"
#include "PdbParserInternal.h"
#include "PdbFile.h"
#include "PdbModule.h"
#include "PdbModuleDetails.h"

//	------------------------------------------------------------------------------------------------
//	------------------------------------------------------------------------------------------------
const wchar_t*	TEXT_PDB_FILE_EXTENSION	= L".pdb";

//	------------------------------------------------------------------------------------------------
//	------------------------------------------------------------------------------------------------
PdbFile::PdbFile( PdbParserInternal* parser, const std::wstring& path ) :
	m_pPdbParser( parser ),
	m_pIDiaSession( NULL ), 
	m_pIDiaSymbol( NULL ),
	m_sFileName( path )
{
}
//	------------------------------------------------------------------------------------------------
//	------------------------------------------------------------------------------------------------
PdbFile::~PdbFile()
{
	Cleanup();
}
//	------------------------------------------------------------------------------------------------
//	------------------------------------------------------------------------------------------------
void PdbFile::Close()
{
	Cleanup();
}
//	------------------------------------------------------------------------------------------------
//	------------------------------------------------------------------------------------------------
void PdbFile::Cleanup()
{
	//	Clean Translation Map
	std::vector<IPdbModule*>::iterator it = m_vectorSymbols.begin();
	for( ;it!=m_vectorSymbols.end(); it++)
	{
		PdbModule* pPdbSymbol = (PdbModule*)*it;
		delete pPdbSymbol;
	}
	m_vectorSymbols.clear();

	if ( m_pIDiaSymbol ) 
	{
		m_pIDiaSymbol->Release();
		m_pIDiaSymbol = NULL;
	}
	if ( m_pIDiaSession ) 
	{
		m_pIDiaSession->Release();
		m_pIDiaSession = NULL;
	}
}
//	------------------------------------------------------------------------------------------------
// Load a PDB file
//	------------------------------------------------------------------------------------------------
bool PdbFile::Load( const std::wstring& sFileName )
{
	if( sFileName.size()==0 )
	{
		return false;
	}

	bool bRet = false;

	//	Extract file extension
	wchar_t wszExt[MAX_PATH];
	if( _wsplitpath_s( sFileName.c_str(), NULL, 0, NULL, 0, NULL, 0, wszExt, MAX_PATH)==0 )
	{
		//	PDB File?
		if( _wcsicmp( wszExt, TEXT_PDB_FILE_EXTENSION )==0 )
		{
			// Open (WITHOUT validation) the PDB file as a debug data source
			if( LoadSymbolsFileWithoutValidation( sFileName ) )
			{
				// Retrieve a reference to the global scope
				bRet = m_pIDiaSession->get_globalScope( &m_pIDiaSymbol )==S_OK?true:false;
				_ASSERT( bRet );
			}
		}
	}
	return bRet;
}
bool PdbFile::LoadSymbolsFileWithoutValidation(const std::wstring& sPdbFileName)
{
	bool bRet = false;

	//	Retrieve the DIA datasource
	IDiaDataSource* pIDiaDataSource = m_pPdbParser->GetDiaDataSource();

	if(pIDiaDataSource)
	{
		bool bContinue = false;

		//	Load the PDB file
		HRESULT hr = pIDiaDataSource->loadDataFromPdb(sPdbFileName.c_str());
		if(SUCCEEDED(hr))
		{
			bContinue = true;
		}
		else
		{
			switch(hr)
			{
				//	Failed to open the file, or determined that the file has an invalid format.
			case E_PDB_NOT_FOUND:
				break;
				//	Attempted to access a file with an obsolete format.
			case E_PDB_FORMAT:
				break;
				//	Invalid parameter.
			case E_INVALIDARG:
				break;
				//	Data source has already been prepared.
			case E_UNEXPECTED:
				bContinue = true;
				break;
			default:
				break;
			}
		}
		
		if(bContinue)
		{
			// Open a session for querying symbols
			bRet = pIDiaDataSource->openSession( &m_pIDiaSession )==S_OK?true:false;
		}
	}
	return bRet;
}
GUID PdbFile::GetGuid() const
{
	GUID guid = GUID_NULL;
	if( m_pIDiaSymbol )
	{
		HRESULT hr = m_pIDiaSymbol->get_guid( &guid );
		if(hr==S_OK)
		{
			LPOLESTR lp = NULL;
			hr = StringFromCLSID( guid, &lp );
			if(hr==S_OK)
			{
				CoTaskMemFree(lp);
			}
		}
	}
	return guid;
}
bool PdbFile::IsStripped()
{
	bool bRet = false;
	if( m_pIDiaSymbol )
	{
		BOOL b = FALSE;
		HRESULT hr = m_pIDiaSymbol->get_isStripped(&b);
		if(hr==S_OK)
		{
			bRet = b?true:false;
		}
	}
	return bRet;
}

std::vector<IPdbModule*>& PdbFile::GetModules()
{
	//	Cleanup Translations Map from previous call
	std::vector<IPdbModule*>::iterator it = m_vectorSymbols.begin();
	for( ;it!=m_vectorSymbols.end(); it++)
	{
		PdbModule* module = (PdbModule*) *it;
		delete module;
	}
	m_vectorSymbols.clear();

	if( m_pIDiaSymbol )
	{
		IDiaEnumSymbols* pIDiaEnumSymbols = NULL;

		HRESULT hr = m_pIDiaSymbol->findChildren( 
			SymTagCompiland, 
			NULL, 
			nsNone, 
			&pIDiaEnumSymbols );

		if(hr==S_OK)
		{
			LONG lCount = 0;
			hr = pIDiaEnumSymbols->get_Count( &lCount );
			
			IDiaSymbol* pIDiaSymbol = NULL;
			for(DWORD dwPos=0; dwPos<(DWORD)lCount; dwPos++)
			{
				hr = pIDiaEnumSymbols->Item( dwPos, &pIDiaSymbol );
				if(hr==S_OK)
				{
					PdbModule* pSymbol = new PdbModule( this, pIDiaSymbol );
					
					//	Keep this symbol in the List? (e.g. Reject Symbol beginning with "Import:")
					if( pSymbol->Reject() )
					{
						delete pSymbol;
						pSymbol = NULL;
					}
					else
					{
						m_vectorSymbols.push_back( pSymbol );
					}
				}
			}
			pIDiaEnumSymbols->Release();
		}
	}
	return m_vectorSymbols;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer winitor
Germany Germany
Marc Ochsenmeier is the author of pestudio (www.winitor.com) and worked as developer with the focus on Windows Security. He now works as a Malware Analyst

pestudio is on twitter at: https://twitter.com/ochsenmeier

Comments and Discussions