Click here to Skip to main content
15,884,629 members
Articles / Web Development / HTML

Catch All Bugs with BugTrap!

Rate me:
Please Sign up or sign in to vote.
4.34/5 (84 votes)
31 Jan 2009MIT5 min read 1.8M   9.1K   292  
A tool that can catch unhandled errors and exceptions, and deliver error reports to remote support servers
/*
 * This is a part of the BugTrap package.
 * Copyright (c) 2005-2007 IntelleSoft.
 * All rights reserved.
 *
 * Description: Map file processor.
 * Author: Maksim Pyatkovskiy.
 *
 * This source code is only intended as a supplement to the
 * BugTrap package reference and related electronic documentation
 * provided with the product. See these sources for detailed
 * information regarding the BugTrap package.
 */

#include "StdAfx.h"
#include "MapProcessor.h"
#include "ComError.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

IMPLEMENT_RUNTIME_CLASS(CMapProcessor, CBaseProcessor)

void CMapProcessor::Clear()
{
	m_ptrPreferredBaseAddress = NULL;
	m_ptrBaseAddress = NULL;
	m_plstPubFns.reset();
	m_plstFilesList.reset();
	m_strMapText.clear();
}

/**
 * @param strMapText - map file text.
 */
void CMapProcessor::SetMapText(const std::string& strMapText)
{
	Clear();
	m_strMapText.assign(strMapText);
	m_ptrBaseAddress = GetPreferredBaseAddress();
}

/**
 * @param pszMapText - map file text.
 */
void CMapProcessor::SetMapText(PCSTR pszMapText)
{
	Clear();
	m_strMapText.assign(pszMapText);
	m_ptrBaseAddress = GetPreferredBaseAddress();
}

/**
 * @param pchMapText - map file text.
 * @param uMapTextLength - length of map file text.
 */
void CMapProcessor::SetMapText(const CHAR* pchMapText, UINT uMapTextLength)
{
	Clear();
	m_strMapText.assign(pchMapText, uMapTextLength);
	m_ptrBaseAddress = GetPreferredBaseAddress();
}

/**
 * @return module preferred base address.
 */
PVOID CMapProcessor::GetPreferredBaseAddress() const
{
	if (m_ptrPreferredBaseAddress == NULL && ! m_strMapText.empty())
	{
		boost::regex expression("Preferred load address is ([[:xdigit:]]+)");
		boost::match_results<std::string::const_iterator> what;
		if (boost::regex_search(m_strMapText, what, expression))
		{
			std::string strPreferredBaseAddress(what[1]);
			m_ptrPreferredBaseAddress = (PVOID)_strtoui64(strPreferredBaseAddress.c_str(), NULL, 16);
		}
	}
	return m_ptrPreferredBaseAddress;
}

/**
 * @return list of public functions.
 */
boost::shared_ptr< std::list<CMapFnInfo> > CMapProcessor::GetPublicFunctions() const
{
	if (! m_plstPubFns && ! m_strMapText.empty())
	{
		m_plstPubFns.reset(new std::list<CMapFnInfo>);
		boost::match_results<std::string::const_iterator> what;
		std::string::const_iterator end = m_strMapText.end();
		/* 0001:00019df3 Function 1001adf3 f Library:File.obj */
		boost::regex expressionEntry("\\A *([[:xdigit:]]+):([[:xdigit:]]+) +(\\S+) +([[:xdigit:]]+)(?: f)?(?: i)? +(?:(\\S+):)?(\\S+)\r\n");

		boost::regex expressionGlobals("Address +Publics by Value +Rva\\+Base +Lib:Object\r\n\r\n");
		if (boost::regex_search(m_strMapText, what, expressionGlobals))
		{
			std::string::const_iterator start = what[0].second;
			while (boost::regex_search(start, end, what, expressionEntry))
			{
				UINT uSection = strtoul(what[1].str().c_str(), NULL, 16);
				PVOID ptrOffset = (PVOID)_strtoui64(what[2].str().c_str(), NULL, 16);
				const std::string& strFunction = what[3].str();
				PVOID ptrRvaBase = (PVOID)_strtoui64(what[4].str().c_str(), NULL, 16);
				const std::string& strLibrary = what[5].str();
				const std::string& strObject = what[6].str();
				PVOID ptrAddress = (PVOID)((INT_PTR)ptrRvaBase - (INT_PTR)m_ptrPreferredBaseAddress + (INT_PTR)m_ptrBaseAddress);
				CMapFnInfo fnInfo(ptrAddress, uSection, ptrOffset, strFunction, ptrRvaBase, strLibrary, strObject);
				m_plstPubFns->push_back(fnInfo);
				start = what[0].second;
			}
		}

		boost::regex expressionStatic("Static symbols\r\n\r\n");
		if (boost::regex_search(m_strMapText, what, expressionStatic))
		{
			std::string::const_iterator start = what[0].second;
			while (boost::regex_search(start, end, what, expressionEntry))
			{
				UINT uSection = strtoul(what[1].str().c_str(), NULL, 16);
				PVOID ptrOffset = (PVOID)_strtoui64(what[2].str().c_str(), NULL, 16);
				const std::string& strFunction = what[3].str();
				PVOID ptrRvaBase = (PVOID)_strtoui64(what[4].str().c_str(), NULL, 16);
				const std::string& strLibrary = what[5].str();
				const std::string& strObject = what[6].str();
				PVOID ptrAddress = (PVOID)((INT_PTR)ptrRvaBase - (INT_PTR)m_ptrPreferredBaseAddress + (INT_PTR)m_ptrBaseAddress);
				CMapFnInfo fnInfo(ptrAddress, uSection, ptrOffset, strFunction, ptrRvaBase, strLibrary, strObject);
				m_plstPubFns->push_back(fnInfo);
				start = what[0].second;
			}
		}

		m_plstPubFns->sort(&CompareFns);
	}
	return m_plstPubFns;
}

/**
 * @param ptrAddress - function address.
 * @param rFnInfo - pointer to function info block.
 * @param dwDisplacement64 - symbol displacement.
 * @return true if function info has been found.
 */
bool CMapProcessor::FindFunctionInfo(PVOID ptrAddress, CMapFnInfo& rFnInfo, DWORD64& dwDisplacement64) const
{
	boost::shared_ptr< std::list<CMapFnInfo> > plstPubFns(GetPublicFunctions());
	if (plstPubFns.get() && ! plstPubFns->empty())
	{
		std::string strEmpty;
		CMapFnInfo fnKey(ptrAddress, 0u, NULL, strEmpty, NULL, strEmpty, strEmpty);
		std::list<CMapFnInfo>::iterator itFirstFn = plstPubFns->begin();
		std::list<CMapFnInfo>::iterator itLastFn = plstPubFns->end();
		std::list<CMapFnInfo>::iterator itNextFn = std::upper_bound(itFirstFn, itLastFn, fnKey, &CompareFns);
		if (itNextFn != itFirstFn)
		{
			--itNextFn;
			rFnInfo = *itNextFn;
			dwDisplacement64 = (DWORD64)((INT_PTR)ptrAddress - (INT_PTR)rFnInfo.GetAddress());
			return true;
		}
	}
	rFnInfo = CMapFnInfo();
	dwDisplacement64 = 0;
	return false;
}

/**
 * @return list of source files.
 */
boost::shared_ptr< std::list<CMapFileData> > CMapProcessor::GetFilesList() const
{
	if (! m_plstFilesList && ! m_strMapText.empty())
	{
		m_plstFilesList.reset(new std::list<CMapFileData>);
		boost::match_results<std::string::const_iterator> what;
		std::string::const_iterator start = m_strMapText.begin();
		std::string::const_iterator end = m_strMapText.end();
		/* 140 0001:00010788   141 0001:0001078b   142 0001:00010798   143 0001:0001079b */
		boost::regex expressionLine("\\A *(\\d+) ([[:xdigit:]]+):([[:xdigit:]]+)\\s+");
		/* Line numbers for C:\Path1\Library.lib(D:\Path2\File.c) segment .text */
		boost::regex expressionFile("Line numbers for ([^\\(]+)\\(([^\\)]+)\\) segment (\\S+)\r\n\r\n");
		while (boost::regex_search(start, end, what, expressionFile))
		{
			CMapFileInfo fileInfo(what[1].str(), what[2].str(), what[3].str());
			m_plstFilesList->push_back(fileInfo);
			std::list<CMapLineInfo>& rLinesInfo = m_plstFilesList->back().GetLines();
			start = what[0].second;
			while (boost::regex_search(start, end, what, expressionLine))
			{
				UINT uLineNumber = atol(what[1].str().c_str());
				UINT uSection = strtoul(what[2].str().c_str(), NULL, 16);
				PVOID ptrOffset = (PVOID)_strtoui64(what[3].str().c_str(), NULL, 16);
				PVOID ptrAddress = GetImageAddress(ptrOffset);
				CMapLineInfo lineInfo(ptrAddress, uSection, ptrOffset, uLineNumber);
				rLinesInfo.push_back(lineInfo);
				start = what[0].second;
			}
			rLinesInfo.sort(CompareLns);
		}
	}
	return m_plstFilesList;
}

/**
 * @param ptrAddress - line address.
 * @param rFileInfo - pointer to file information.
 * @param rLineInfo - pointer to line number information.
 * @param dwDisplacement32 - symbol displacement.
 * @return true if line was found.
 */
bool CMapProcessor::FindLineInfo(PVOID ptrAddress, CMapFileInfo& rFileInfo, CMapLineInfo& rLineInfo, DWORD& dwDisplacement32) const
{
	const CMapFileInfo* pFileInfo = NULL;
	const CMapLineInfo* pLineInfo = NULL;
	dwDisplacement32 = 0;
	boost::shared_ptr< std::list<CMapFileData> > plstFilesList(GetFilesList());
	if (plstFilesList.get() && ! plstFilesList->empty())
	{
		CMapLineInfo lnKey(ptrAddress, 0u, NULL, 0u);
		std::list<CMapFileData>::iterator itFirstFile = plstFilesList->begin();
		std::list<CMapFileData>::iterator itLastFile = plstFilesList->end();
		for (std::list<CMapFileData>::iterator itFile = itFirstFile; itFile != itLastFile; ++itFile)
		{
			std::list<CMapLineInfo>& rLines = itFile->GetLines();
			if (! rLines.empty() && rLines.front().GetAddress() <= ptrAddress && ptrAddress <= rLines.back().GetAddress())
			{
				std::list<CMapLineInfo>::iterator itFirstLn = rLines.begin();
				std::list<CMapLineInfo>::iterator itLastLn = rLines.end();
				std::list<CMapLineInfo>::iterator itNextLn = std::upper_bound(itFirstLn, itLastLn, lnKey, CompareLns);
				if (itNextLn != itFirstLn)
				{
					--itNextLn;
					if (pLineInfo == NULL || itNextLn->GetAddress() > pLineInfo->GetAddress())
					{
						pFileInfo = &*itFile;
						pLineInfo = &*itNextLn;
						dwDisplacement32 = (DWORD)((INT_PTR)ptrAddress - (INT_PTR)pLineInfo->GetAddress());
					}
				}
			}
		}
	}
	if (pFileInfo != NULL && pLineInfo != NULL)
	{
		rFileInfo = *pFileInfo;
		rLineInfo = *pLineInfo;
		return true;
	}
	else
	{
		rFileInfo = CMapFileInfo();
		rLineInfo = CMapLineInfo();
		return false;
	}
}

/**
 * @param pszFileName - MAP file name.
 */
void CMapProcessor::LoadMapText(PCTSTR pszFileName)
{
	Clear();
	CAtlFile fileMap;
	HRESULT hRes = fileMap.Create(pszFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
	CHECK_HRESULT(hRes);
	ULONGLONG ullFileSize;
	fileMap.GetSize(ullFileSize);
	UINT uFileLength = (UINT)ullFileSize;
	boost::scoped_array<CHAR> pchMapBuffer(new CHAR[uFileLength]);
	fileMap.Read(pchMapBuffer.get(), uFileLength);
	SetMapText(pchMapBuffer.get(), uFileLength);
}

/**
 * @param ptrAddress - function address.
 * @param dwDisplacement64 - symbol displacement.
 * @param pFnInfo - pointer to function info block.
 * @return true if function info has been found.
 */
bool CMapProcessor::FindFunctionInfo(PVOID ptrAddress, boost::shared_ptr<CBaseFnInfo>& pFnInfo, DWORD64& dwDisplacement64) const
{
	CMapFnInfo FnInfo;
	if (FindFunctionInfo(ptrAddress, FnInfo, dwDisplacement64))
	{
		pFnInfo.reset(new CMapFnInfo(FnInfo));
		return true;
	}
	else
	{
		pFnInfo.reset();
		return false;
	}
}

/**
 * @param ptrAddress - line address.
 * @param pFileInfo - pointer to file information.
 * @param pLineInfo - pointer to line number information.
 * @param dwDisplacement32 - symbol displacement.
 * @return true if line was found.
 */
bool CMapProcessor::FindLineInfo(PVOID ptrAddress, boost::shared_ptr<CBaseFileInfo>& pFileInfo, boost::shared_ptr<CBaseLineInfo>& pLineInfo, DWORD& dwDisplacement32) const
{
	CMapFileInfo FileInfo;
	CMapLineInfo LineInfo;
	if (FindLineInfo(ptrAddress, FileInfo, LineInfo, dwDisplacement32))
	{
		pFileInfo.reset(new CMapFileInfo(FileInfo));
		pLineInfo.reset(new CMapLineInfo(LineInfo));
		return true;
	}
	else
	{
		pFileInfo.reset();
		pLineInfo.reset();
		return false;
	}
}

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 MIT License


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions