/util/drmingw: 0e9b7ae0ec29: Add support for reading debug symbo...

Daniel Atallah datallah at pidgin.im
Mon Sep 10 12:11:13 EDT 2012


Changeset: 0e9b7ae0ec290f49f4deb06814e8cf3a0d701aae
Author:	 Daniel Atallah <datallah at pidgin.im>
Date:	 2012-09-08 12:50 -0400
Branch:	 default
URL: http://hg.pidgin.im/util/drmingw/rev/0e9b7ae0ec29

Description:

Add support for reading debug symbols from external files alongside the modules.

This makes it possible to generate useful crash reports from stripped binaries
by reading the symbols from a unstripped copy of the binary.

By default, it only looks for a "module.ext.dbgsym" file in the same directory
as the module. An alternate directory structure for looking up debug symbols can
be specified by calling "SetDebugInfoDir" on the loaded exchndl.dll instance.

The DebugInfoDir is intended to be a parallel directory structure to the
stripped application structure containing the corresponding ".dbgsym" files.

If the module has version information embedded, a comparison is done to make
sure that the corresponding "debug symbols" module has the same version
information specified.

diffstat:

 exchndl.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 106 insertions(+), 6 deletions(-)

diffs (191 lines):

diff --git a/exchndl.c b/exchndl.c
--- a/exchndl.c
+++ b/exchndl.c
@@ -19,13 +19,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <malloc.h>
+#include <sys/stat.h>
 
 
 #define HAVE_BFD	1
 
+#define DEBUG_INFO_SUFFIX _T(".dbgsym")
 
 // Declare the static variables
 static TCHAR szLogFileName[MAX_PATH] = _T("");
+static TCHAR szDebugInfoDir[MAX_PATH] = _T("");
 static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
 static HANDLE hReportFile;
 
@@ -641,12 +644,69 @@ BOOL GetModuleVersionInfo(const TCHAR *s
 }
 
 static
+BOOL LookupDebugSymbolsFile(const TCHAR *szModule, TCHAR *szModuleDebug, DWORD nSize)
+{
+	struct _stat stat_buf;
+
+	_tcscpy(szModuleDebug, _T(""));
+
+	/* Look for a appropriate debuginfo file in the DebugInfoDir*/
+	if (*szDebugInfoDir)
+	{
+		TCHAR* szModuleSubStr;
+		int debugDirLen;
+
+		szModuleSubStr = _tcschr(szModule, _T('\\'));
+		debugDirLen = _tcslen(szDebugInfoDir);
+		while (szModuleSubStr != NULL)
+		{
+			szModuleSubStr++;
+
+			if ((debugDirLen + _tcslen(szModuleSubStr)) < nSize - 1) {
+
+				_tcscpy(szModuleDebug, szDebugInfoDir);
+				_tcscat(szModuleDebug, szModuleSubStr);
+				if (_tstat(szModuleDebug, &stat_buf) == 0)
+					break;
+
+				if ((_tcslen(szModuleDebug) + _tcslen(DEBUG_INFO_SUFFIX)) < nSize - 1)
+				{
+					_tcscat(szModuleDebug, DEBUG_INFO_SUFFIX);
+
+					if (_tstat(szModuleDebug, &stat_buf) == 0)
+						break;
+				}
+			}
+
+			/* Look for one less directory */
+			szModuleSubStr = _tcschr(szModuleSubStr, _T('\\'));
+		}
+
+	}
+
+	/* Look for a modulename.dbgsym file directly alongside the module */
+	if (!(*szDebugInfoDir) || _tstat(szModuleDebug, &stat_buf) != 0)
+	{
+		if ((_tcslen(szModule) + _tcslen(DEBUG_INFO_SUFFIX)) < nSize - 1)
+		{
+			_tcscpy(szModuleDebug, szModule);
+			_tcscat(szModuleDebug, DEBUG_INFO_SUFFIX);
+
+		}
+	}
+
+	return (_tstat(szModuleDebug, &stat_buf) == 0);
+}
+
+
+static
 BOOL StackBackTrace(HANDLE hProcess, HANDLE hThread, PCONTEXT pContext)
 {
 	STACKFRAME StackFrame;
 
 	HMODULE hModule = NULL;
 	TCHAR szModule[MAX_PATH]; 
+	TCHAR szModuleDebug[MAX_PATH];
 
 #ifdef HAVE_BFD
 	bfd *abfd = NULL;
@@ -740,8 +800,6 @@ BOOL StackBackTrace(HANDLE hProcess, HAN
 			);
 		}			
 
-		rprintf( _T("%08lX"), StackFrame.AddrPC.Offset);
-		
 		if((hModule = (HMODULE) GetModuleBase(StackFrame.AddrPC.Offset))
 			       && GetModuleFileName(hModule, szModule, sizeof(szModule) / sizeof(TCHAR)))
 		{
@@ -749,20 +807,31 @@ BOOL StackBackTrace(HANDLE hProcess, HAN
 #ifndef HAVE_BFD
 			rprintf( _T("  %s:ModulBase %08lX"), szModule, hModule);
 #else /* HAVE_BFD */
-			rprintf( _T("  %s:%08lX"), szModule, StackFrame.AddrPC.Offset);
 		
 			if(hModule != hPrevModule)
 			{
+				BOOL hasDebugInfoFile;
 				DWORD dwVInfo[4];
 
+				hasDebugInfoFile = LookupDebugSymbolsFile(szModule, szModuleDebug, sizeof(szModule) / sizeof(TCHAR));
+
 				if (GetModuleVersionInfo(szModule, dwVInfo))
 				{
 					rprintf(_T("         %s [%d.%d.%d.%d]\r\n"),
 						szModule,
 						dwVInfo[0], dwVInfo[1], dwVInfo[2], dwVInfo[3]);
 
+					DWORD dwVInfo2[4];
+					if (hasDebugInfoFile)
+						hasDebugInfoFile = GetModuleVersionInfo(szModuleDebug, dwVInfo2)
+							&& (dwVInfo[0] == dwVInfo2[0]
+								&& dwVInfo[1] == dwVInfo2[1]
+								&& dwVInfo[2] == dwVInfo2[2]
+								&& dwVInfo[3] == dwVInfo2[3]);
 				}
 
+				/* If there is no version info, we try to use the debuginfo file by default (if it exists) */
+
 				if(syms)
 				{
 					free(syms);
@@ -772,8 +841,19 @@ BOOL StackBackTrace(HANDLE hProcess, HAN
 				
 				if(abfd)
 					bfd_close(abfd);
-				
-				if((abfd = bfd_openr (szModule, NULL)))
+				abfd = NULL;
+
+				if (hasDebugInfoFile)
+				{
+					if ((abfd = bfd_openr (szModuleDebug, NULL)))
+						rprintf(_T("         Using Debug Symbols from: %s\r\n"),
+							szModuleDebug);
+					else
+						hasDebugInfoFile = FALSE;
+				}
+
+				if(abfd || (abfd = bfd_openr (szModule, NULL)))
+				{
 					if(bfd_check_format(abfd, bfd_object))
 					{
 						bfd_vma adjust_section_vma = 0;
@@ -796,8 +876,10 @@ BOOL StackBackTrace(HANDLE hProcess, HAN
 							/* Read in the symbol table.  */
 							slurp_symtab(abfd, &syms, &symcount);
 					}
+				}
 			}
-			
+
+			rprintf( _T("%08lX %s"), StackFrame.AddrPC.Offset, szModule);
 			if(!bSuccess && abfd && syms && symcount)
 				if((bSuccess = BfdGetSymFromAddr(abfd, syms, symcount, StackFrame.AddrPC.Offset, szSymName, sizeof(szSymName) / sizeof(TCHAR))))
 				{
@@ -1257,6 +1339,24 @@ void OnExit(void)
 	szLogFileName[bufSize - 1] = _T('\0');
 }
 
+__declspec(dllexport) void __cdecl SetDebugInfoDir(const char *debugInfoDir);
+__declspec(dllexport) void __cdecl SetDebugInfoDir(const char *debugInfoDir)
+{
+	int bufSize = sizeof(szDebugInfoDir) / sizeof(TCHAR);
+	if (!debugInfoDir || _tcslen(debugInfoDir) > bufSize - 2) {
+		printf("Specified DebugInfoDir(%s) is too long or invalid\n", debugInfoDir);
+		_tcscpy(szDebugInfoDir, _T(""));
+		return;
+	}
+	TCHAR lastChar;
+	_tcsncpy(szDebugInfoDir, debugInfoDir, bufSize - 2);
+	szDebugInfoDir[bufSize - 2] = _T('\0');
+	/* Append a  '\' if there isn't one - we've made sure that we have room for one */
+	lastChar = szDebugInfoDir[_tcslen(szDebugInfoDir) - 1];
+	if (lastChar != _T('\\') && lastChar != _T('/'))
+		_tcscat(szDebugInfoDir, _T("\\"));
+}
+
 #if 0
 BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
 {



More information about the Commits mailing list