///////////////////////////////////////////////////////////////////////////////
//
// SymLoad.cpp 
// 
// Author: Oleg Starodumov
// 
//


///////////////////////////////////////////////////////////////////////////////
// 
// Description: 
// 
// This example shows how to: 
// 
//   * Initialize DbgHelp 
//   * Load symbols for a module 
//   * Check what kind of symbols is loaded 
//   * Unload symbols for the module 
//   * Deinitialize DbgHelp 
//
// Actions: 
// 
//   * Enable debug option 
//   * Initialize DbgHelp 
//   * Load symbols for the module 
//   * Obtain and display information about loaded symbols 
//   * Unload symbols for the module 
//   * Deinitialize DbgHelp 
//
// Command line parameters: 
// 
//   * Path to the module you want to load symbols for 
//


///////////////////////////////////////////////////////////////////////////////
// Include files 
//

#include <windows.h>
#include <tchar.h>

#include <dbghelp.h>

#include <stdio.h>


///////////////////////////////////////////////////////////////////////////////
// Directives 
//

#pragma comment( lib, "dbghelp.lib" )


///////////////////////////////////////////////////////////////////////////////
// Declarations 
//

void ShowSymbolInfo( DWORD64 ModBase ); 


///////////////////////////////////////////////////////////////////////////////
// main 
//

int _tmain( int argc, const TCHAR* argv[] ) 
{
	BOOL bRet = FALSE; 


	// Check command line parameters 

	if( argc < 2 ) 
	{
		_tprintf( _T("Usage: %s <ModulePathAndName> \n"), argv[0] ); 
		return 0; 
	}


	// Set options 

	DWORD Options = SymGetOptions(); 

		// SYMOPT_DEBUG option asks DbgHelp to print additional troubleshooting 
		// messages to debug output - use the debugger's Debug Output window 
		// to view the messages 

	Options |= SYMOPT_DEBUG; 

	::SymSetOptions( Options ); 


	// Initialize DbgHelp and load symbols for all modules of the current process 

	bRet = ::SymInitialize ( 
	            GetCurrentProcess(),  // Process handle of the current process 
	            NULL,                 // No user-defined search path -> use default 
	            FALSE                 // Do not load symbols for modules in the current process 
	          ); 

	if( !bRet ) 
	{
		_tprintf(_T("Error: SymInitialize() failed. Error code: %u \n"), ::GetLastError());
		return 0; 
	}


	// Load symbols for the module 

	const TCHAR* pModName = argv[1]; 

	_tprintf( _T("Loading symbols for module %s ... \n"), pModName ); 

	DWORD64 ModBase = ::SymLoadModule64 ( 
	            GetCurrentProcess(), // Process handle of the current process 
	            NULL,                // Handle to the module's image file (not needed)
	            pModName,            // Path/name of the module 
	            NULL,                // User-defined short name of the module (it can be NULL) 
	            0,                   // Base address of the module (can be NULL) 
	            0                    // Size of the module (can be NULL) 
	          ); 

	if( ModBase == 0 ) 
	{
		_tprintf(_T("Error: SymLoadModule64() failed. Error code: %u \n"), ::GetLastError());
		return 0; 
	}
	else 
	{
		_tprintf( _T("Load address: %I64x \n"), ModBase ); 


		// Obtain and display information about loaded symbols 

		ShowSymbolInfo( ModBase ); 


		// Unload symbols for the module 

		bRet = ::SymUnloadModule64( GetCurrentProcess(), ModBase ); 

		if( !bRet )
		{
			_tprintf( _T("Error: SymUnloadModule64() failed. Error code: %u \n"), ::GetLastError() ); 
		}
	}


	// Deinitialize DbgHelp 

	bRet = ::SymCleanup( GetCurrentProcess() ); 

	if( !bRet ) 
	{
		_tprintf(_T("Error: SymCleanup() failed. Error code: %u \n"), ::GetLastError());
		return 0; 
	}


	// Complete 

	return 0; 
}


///////////////////////////////////////////////////////////////////////////////
// Functions 
//

void ShowSymbolInfo( DWORD64 ModBase ) 
{
	// Get module information 

	IMAGEHLP_MODULE64 ModuleInfo; 

	memset(&ModuleInfo, 0, sizeof(ModuleInfo) ); 

	ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); 

	BOOL bRet = ::SymGetModuleInfo64( GetCurrentProcess(), ModBase, &ModuleInfo ); 

	if( !bRet ) 
	{
		_tprintf(_T("Error: SymGetModuleInfo64() failed. Error code: %u \n"), ::GetLastError());
		return; 
	}


	// Display information about symbols 

		// Kind of symbols 

	switch( ModuleInfo.SymType ) 
	{
		case SymNone: 
			_tprintf( _T("No symbols available for the module.\n") ); 
			break; 

		case SymExport: 
			_tprintf( _T("Loaded symbols: Exports\n") ); 
			break; 

		case SymCoff: 
			_tprintf( _T("Loaded symbols: COFF\n") ); 
			break; 

		case SymCv: 
			_tprintf( _T("Loaded symbols: CodeView\n") ); 
			break; 

		case SymSym: 
			_tprintf( _T("Loaded symbols: SYM\n") ); 
			break; 

		case SymVirtual: 
			_tprintf( _T("Loaded symbols: Virtual\n") ); 
			break; 

		case SymPdb: 
			_tprintf( _T("Loaded symbols: PDB\n") ); 
			break; 

		case SymDia: 
			_tprintf( _T("Loaded symbols: DIA\n") ); 
			break; 

		case SymDeferred: 
			_tprintf( _T("Loaded symbols: Deferred\n") ); // not actually loaded 
			break; 

		default: 
			_tprintf( _T("Loaded symbols: Unknown format.\n") ); 
			break; 
	}

		// Image name 

	if( _tcslen( ModuleInfo.ImageName ) > 0 ) 
	{
		_tprintf( _T("Image name: %s \n"), ModuleInfo.ImageName ); 
	}

		// Loaded image name 

	if( _tcslen( ModuleInfo.LoadedImageName ) > 0 ) 
	{
		_tprintf( _T("Loaded image name: %s \n"), ModuleInfo.LoadedImageName ); 
	}

		// Loaded PDB name 

	if( _tcslen( ModuleInfo.LoadedPdbName ) > 0 ) 
	{
		_tprintf( _T("PDB file name: %s \n"), ModuleInfo.LoadedPdbName ); 
	}

		// Is debug information unmatched ? 
		// (It can only happen if the debug information is contained 
		// in a separate file (.DBG or .PDB) 

	if( ModuleInfo.PdbUnmatched || ModuleInfo.DbgUnmatched ) 
	{
		_tprintf( _T("Warning: Unmatched symbols. \n") ); 
	}

		// Contents 

			// Line numbers available ? 

	_tprintf( _T("Line numbers: %s \n"), ModuleInfo.LineNumbers ? _T("Available") : _T("Not available") ); 

			// Global symbols available ? 

	_tprintf( _T("Global symbols: %s \n"), ModuleInfo.GlobalSymbols ? _T("Available") : _T("Not available") ); 

			// Type information available ? 

	_tprintf( _T("Type information: %s \n"), ModuleInfo.TypeInfo ? _T("Available") : _T("Not available") ); 

			// Source indexing available ? 

	_tprintf( _T("Source indexing: %s \n"), ModuleInfo.SourceIndexed ? _T("Yes") : _T("No") ); 

			// Public symbols available ? 

	_tprintf( _T("Public symbols: %s \n"), ModuleInfo.Publics ? _T("Available") : _T("Not available") ); 


}


