Click here to Skip to main content
15,888,579 members
Articles / Programming Languages / C#

Using PDB files and symbols to debug your application

Rate me:
Please Sign up or sign in to vote.
4.83/5 (5 votes)
18 Apr 2011CPOL13 min read 59.5K   1.1K   25  
With the help of PDB files, you are able to recover the source code as it was before compilation from the bits and bytes at runtime.
#include "SymbolHandler.h"
#include "SymbolFunctionEntry.h"

SymbolHandler::SymbolHandler()
{
	// The second parameter can point to a list of strings separated by comma where
	// symbol files should be searched (which means where the PDB should be searched).
	// For example "C:\\Symbols;C:\\Development\\Symbols". If its NULL the default
	// paths are used which are the current folder, the _NT_SYMBOL_PATH environment
	// variable and the _NT_ALTERNATE_SYMBOL_PATH environment variable. (you can use
	// getenv to get the values of them).
	// The third parameter tells if it should also try to load symbols for all DLLs
	// in the current process.
	BOOL ret = SymInitialize(GetCurrentProcess(), NULL, TRUE);
	
	// return FALSE here does not actually mean that it failed, it also returns false
	// if the symbols are already loaded. So we need to use GetLastError to know what
	// actually happened and act accordingly.
	if(ret == FALSE)
	{
		DWORD err = GetLastError();

		// If the symbols are already loaded it returns an invalid parameter error
		// That of course is a bit bad because it could also mean that we really had
		// a bad parameter. Thats why printing out a message is a good idea!
		if(err == ERROR_INVALID_PARAMETER)
		{
			OutputDebugString("Warning: SymInitialize returned ERROR_INVALID_PARAMETER. This could mean that an error happened "\
				"or just that symbol are already loaded!\n");

			// We are already loaded so lets just update things:
			SymRefreshModuleList(GetCurrentProcess());
		}
		else
			throw std::exception("Failed to initialize symbols! See last error for more information.");
	}
}

bool SymbolHandler::IsFunctionPresent(const char* name)
{ 
	SYMBOL_INFO sym;
	sym.SizeOfStruct = sizeof(sym);
	sym.MaxNameLen = 1;
	// SymGetSymFromName tries to search a symbol by its name
	// In fact this would also catch symbols for global variables for example
	// which have the same name.
	if(SymFromName(GetCurrentProcess(), name, &sym) == FALSE)
		return false;
	
	if(sym.Tag != SymTagFunction)
		return false;

	return true;
}

PSYMBOL_INFO SymbolHandler::AllocSymbol(int nameLen)
{
	void* space = malloc(sizeof(SYMBOL_INFO) + nameLen);
	memset(space, 0, sizeof(SYMBOL_INFO) + nameLen);
	PSYMBOL_INFO sym = reinterpret_cast<PSYMBOL_INFO>(space);
	sym->NameLen = nameLen;
	// SizeOfStruct is ment to point at the actual size of the struct and not
	// of the whole memory allocated
	sym->SizeOfStruct = sizeof(SYMBOL_INFO);
	return sym;
}

void SymbolHandler::FreeSymbol(PSYMBOL_INFO symbol)
{
	free(symbol);
}

bool SymbolHandler::GetFunction(const char* name, SymbolFunctionEntry& symbol)
{
	PSYMBOL_INFO sym = AllocSymbol(MAX_SYM_NAME);
	if(SymFromName(GetCurrentProcess(), name, sym) == FALSE)
	{
		FreeSymbol(sym);
		return false;
	}

	if(sym->Tag != SymTagFunction)
	{
		FreeSymbol(sym);
		return false;
	}

	symbol.m_symbol = sym;
	return true;
}

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
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions