Skip to content

Instantly share code, notes, and snippets.

@gabonator
Created May 8, 2012 18:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save gabonator/2638372 to your computer and use it in GitHub Desktop.
Save gabonator/2638372 to your computer and use it in GitHub Desktop.
Windows CE stack dumping
void DeviceExceptionHandler( void *pep )
{
if ( !_DeviceExceptionHandler((LPEXCEPTION_POINTERS)pep) )
{
MessageBox(NULL, _T("Cannot generate dumpreport!"), _T("Illegal operation report"), MB_OK);
}
}
#include <Tlhelp32.h>
#include <vector>
using namespace std;
struct MyModuleInfo
{
BYTE* Base;
HMODULE Handle;
DWORD Size;
enum { MaxNameLen = 36 };
TCHAR Name[MaxNameLen];
};
#define IMPORTBEGIN(dll) \
HINSTANCE hTL = LoadLibrary(_T(dll)); \
if (!hTL) \
{ \
DbgPrint(_T("GetModuleList(): Cannot load library '%s'\n"), _T(#dll)); \
return false; \
}
#define IMPORTEND() \
FreeLibrary(hTL);
#define IMPORTLIB(r, s, a) \
typedef r (*_##s)a; \
_##s s = (_##s)GetProcAddress(hTL, _T(#s)); \
if (!s) { DbgPrint(_T("GetModuleList(): Cannot load %s\n"), _T(#s)); return false; }
bool GetModuleList(vector<MyModuleInfo>& moduleList)
{
IMPORTBEGIN("toolhelp.dll")
IMPORTLIB(HANDLE, CreateToolhelp32Snapshot, (DWORD dwFlags, DWORD th32ProcessID))
IMPORTLIB(BOOL32, CloseToolhelp32Snapshot, (HANDLE hSnapshot))
IMPORTLIB(BOOL32, Process32Next, (HANDLE hSnapshot, LPPROCESSENTRY32 lppe))
IMPORTLIB(BOOL32, Process32First, (HANDLE hSnapshot, LPPROCESSENTRY32 lppe))
IMPORTLIB(BOOL32, Module32Next, (HANDLE hSnapshot, LPMODULEENTRY32 lpme))
IMPORTLIB(BOOL32, Module32First, (HANDLE hSnapshot, LPMODULEENTRY32 lpme))
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE | TH32CS_GETALLMODS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
DbgPrint(_T("GetModuleList(): hSnapshot = NULL\n"));
IMPORTEND();
return false;
}
MODULEENTRY32 moduleInfo;
moduleInfo.dwSize = sizeof(moduleInfo);
if (Module32First(hSnapshot, &moduleInfo)) do {
MyModuleInfo myInfo;
myInfo.Handle = moduleInfo.hModule;
myInfo.Base = moduleInfo.modBaseAddr;
myInfo.Size = moduleInfo.modBaseSize;
memcpy(myInfo.Name, moduleInfo.szModule, min(sizeof(myInfo.Name), sizeof(moduleInfo.szModule)));
myInfo.Name[myInfo.MaxNameLen-1] = '\0';
moduleList.push_back(myInfo);
} while (Module32Next(hSnapshot, &moduleInfo));
// The module list obtained above only contains DLLs! To get the EXE files
// also, we must call Process32First and Process32Next in a loop.
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
if (Process32First(hSnapshot, &processInfo)) do {
MyModuleInfo myInfo;
myInfo.Handle = NULL; // No handle given
myInfo.Base = (BYTE*)processInfo.th32MemoryBase;
myInfo.Size = 0x800000; // No size provided! Allow max 8 MB
memcpy(myInfo.Name, processInfo.szExeFile, min(sizeof(myInfo.Name), sizeof(processInfo.szExeFile)));
myInfo.Name[myInfo.MaxNameLen-1] = '\0';
moduleList.push_back(myInfo);
} while(Process32Next(hSnapshot, &processInfo));
// Debug output
for (INT i = 0; i < (INT)moduleList.size(); i++) {
MyModuleInfo& m = moduleList[i];
DbgPrint(_T("%-30s: 0x%08x - 0x%08x\n"), m.Name, (DWORD)m.Base, (DWORD)m.Base + m.Size);
}
CloseToolhelp32Snapshot(hSnapshot);
IMPORTEND();
return true;
}
#define STACKSNAP_RETURN_FRAMES_ON_ERROR 8
typedef struct _CallSnapshot {
DWORD dwReturnAddr;
} CallSnapshot;
extern "C" ULONG GetThreadCallStack (HANDLE hThrd, ULONG dwMaxFrames, LPVOID lpFrames, DWORD dwFlags, DWORD dwSkip);
bool GetCallStack(vector<MyModuleInfo>& moduleList)
{
CallSnapshot frames[100];
HANDLE hThread = GetCurrentThread();
SetLastError(ERROR_SUCCESS);
INT funcCount = GetThreadCallStack(hThread, 100, frames, STACKSNAP_RETURN_FRAMES_ON_ERROR, 0);
INT nGLE = GetLastError();
if ( nGLE != ERROR_SUCCESS )
{
DbgPrint(_T("GetCallStack(): GetLastError() = %d \n"), nGLE);
return false;
}
for (INT i=0; i<funcCount; i++)
{
DWORD dwFrame = frames[i].dwReturnAddr;
DbgPrint(_T("Stack frame 0x%08x"), dwFrame);
for (INT j = 0; j < (INT)moduleList.size(); j++)
{
MyModuleInfo& m = moduleList[j];
if ( (DWORD)m.Base == 0x00010000 )
{
DbgPrint(_T(": %-16s @ 0x%08x"), _T("App"), dwFrame );
break;
}
if ( dwFrame >= (DWORD)m.Base && dwFrame < (DWORD)(m.Base) + m.Size)
{
DbgPrint(_T(": %-16s @ 0x%08x"), m.Name, (dwFrame - (DWORD)m.Base) | 0x10000000 );
break;
}
}
DbgPrint(_T("\n"));
}
return true;
}
void Dump()
{
vector<MyModuleInfo> moduleList;
bool bModuleList = GetModuleList(moduleList);
bool bCallStack = GetCallStack(moduleList);
}
__try
{
// code
}
__except( DeviceExceptionHandler( GetExceptionInformation() ), EXCEPTION_EXECUTE_HANDLER )
{
// show error message
}
// stackdec.cpp : Defines the entry point for the console application.
//
/*
Inspirovane projektom "StackWalker" http://www.codeproject.com/KB/threads/StackWalker.aspx
Z naseho crash reportu (napr. 090101-042250-log.txt) vygeneruje vystup v citatelnom tvare, napr:
Module 'driver.dll' Loaded.
Module 'device.dll' Loaded.
Module 'library.dll' Loaded.
Module 'corenavi.dll' Loaded.
Module 'device.dll' Loaded.
Module 'Aura.exe' Loaded.
Stack:
0x42e1e974> GetCallStack (...ependent\wince\exceptions.cpp: 417)
0x42e1ff48> DumpManual (...ependent\wince\exceptions.cpp: 496)
0x42e20008> _DeviceExceptionHandler (...ependent\wince\exceptions.cpp: 311)
0x42e20094> CLowDevice::DeviceExceptionHandler (...ependent\wince\exceptions.cpp: 14)
0x00011bfc> WinMain (...\sources\aura\source\aura.cpp: 250)
0x400771bc> Unknown
0x400585ac> Unknown
0x4005277c> Unknown
0x4002a524> Unknown
0x4002a814> Unknown
0x4005287c> Unknown
0x432ebf70> _EasterEgg (...\overlays\ntoverlaylabels.cpp: 28)
0x432ec628> CNTOverlayEdit::_OnLabelClick (...\overlays\ntoverlaylabels.cpp: 169)
0x432e6390> CNTOverlayEdit::OnLButtonUp (...ui\overlays\ntoverlayedit.cpp: 477)
0x430062d8> Library::CWnd::WindowProc (...ibrary\source\wnd\wndproc.cpp: 348)
0x432e4954> CNTOverlayEdit::WindowProc (...ui\overlays\ntoverlayedit.cpp: 819)
0x43005538> Library::CWnd::SendMessage (...ibrary\source\wnd\wndproc.cpp: 98)
0x42f47308> Library::CTopWnd::WindowProc (...rary\source\app\container.cpp: 535)
0x43005538> Library::CWnd::SendMessage (...ibrary\source\wnd\wndproc.cpp: 98)
0x42f46e4c> Library::CContainer::SysDispatchMessage (...rary\source\app\container.cpp: 784)
0x42f4aa6c> CApp::Run (...pp\windows\app\windowsapp.cpp: 1241)
0x00011b40> HelperWinMain (...\sources\aura\source\aura.cpp: 221)
0x00011bc0> WinMain (...\sources\aura\source\aura.cpp: 248)
0x00147414> WinMainCRTStartup (...ibc\crtw32\startup\pegwmain.c: 21)
0x4003be54> Unknown
*/
#include "stdafx.h"
#include <dbghelp.h>
#define IMPORTBEGIN(dll) \
HINSTANCE hTL = LoadLibrary(_T(dll)); \
if (!hTL) \
{ \
DbgPrint(_T("Cannot load library '%s'\n"), _T(#dll)); \
return 1; \
}
#define IMPORTEND() \
FreeLibrary(hTL);
#define IMPORTLIB(r, s, a) \
typedef r (__stdcall *_##s)a; \
_##s s = (_##s)GetProcAddress(hTL, #s); \
if (!s) { DbgPrint(_T("Cannot load %s\n"), _T(#s)); return 1; }
#define DbgPrint printf
class MAXLEN
{
public:
CHAR *pStr;
MAXLEN( CHAR* pInStr, int nMaxLen )
{
int nLen = pInStr ? (int) strlen( pInStr ) : 0;
if ( nLen <= nMaxLen )
{
pStr = _strdup( pInStr );
return;
}
pStr = new CHAR[nMaxLen+1];
strcpy(pStr, "...");
strcat(pStr, pInStr + nLen - nMaxLen + 3);
}
~MAXLEN()
{
delete pStr;
}
operator const LPSTR&() const { return pStr; }
};
void Trim( CHAR* pszStr )
{
int i = (int)strlen(pszStr)-1;
while ( i > 0 && pszStr[i] == ' ' )
pszStr[i--] = 0;
}
BOOL Exist( CHAR* pszPath )
{
DWORD fileAttr = GetFileAttributesA( pszPath );
if ( fileAttr == (DWORD)-1 )
return FALSE;
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
if ( argc != 2 )
{
DbgPrint(_T("Crash logfile analyser - 2011 Sygic/gv\n"));
DbgPrint(_T("\n"));
DbgPrint(_T("Specify dumpfile as parameter!\n"));
return 1;
}
IMPORTBEGIN("dbghelp.dll");
IMPORTLIB( BOOL, SymInitialize, ( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ) );
IMPORTLIB( BOOL, SymCleanup, ( IN HANDLE hProcess ) );
IMPORTLIB( DWORD64, SymLoadModule64, ( IN HANDLE hProcess, IN HANDLE hFile,
IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ) );
IMPORTLIB( BOOL, SymGetSymFromAddr64, ( IN HANDLE hProcess, IN DWORD64 dwAddr,
OUT PDWORD64 pdwDisplacement, /*OUT*/ PIMAGEHLP_SYMBOL64 Symbol ) );
IMPORTLIB( BOOL, SymGetLineFromAddr64, ( IN HANDLE hProcess, IN DWORD64 dwAddr,
OUT PDWORD pdwDisplacement, /*OUT*/ PIMAGEHLP_LINE64 Line ) );
IMPORTLIB( DWORD64, SymGetModuleBase64, (HANDLE hProcess, __in DWORD64 dwAddr) );
IMPORTLIB( BOOL, SymGetModuleInfo64, ( HANDLE hProcess, DWORD64 dwAddr, PIMAGEHLP_MODULE64 ModuleInfo ) );
HANDLE hProcess = (HANDLE)-1;
BOOL bFrame = FALSE;
struct SModuleInfo {
CHAR strModuleName[128];
DWORD dwBeginAddr;
DWORD dwEndAddr;
BOOL bLoaded;
} arrModules[1024];
int nModules = 0;
if ( SymInitialize( hProcess, "", FALSE ) )
{
FILE *f = fopen(argv[1], "r");
if (!f)
{
DbgPrint(_T("Cannot open log file!\n"));
return 1;
}
BYTE pSymbolData[sizeof(IMAGEHLP_SYMBOL64) + 1024];
IMAGEHLP_SYMBOL64 *pSym = (IMAGEHLP_SYMBOL64 *)pSymbolData;
pSym->SizeOfStruct = sizeof( IMAGEHLP_SYMBOL64 );
pSym->MaxNameLength = 1023;
IMAGEHLP_LINE64 Line = {0};
Line.SizeOfStruct = sizeof(Line);
while ( !feof(f) )
{
CHAR strLine[1024] = {0};
fgets(strLine, 1024, f);
if ( strlen(strLine) == 56 && strLine[30] == ':' && strLine[43] == '-' )
{
DWORD dwBegin, dwEnd;
CHAR strModule[128] = {0};
if ( sscanf( strLine, "%30c: 0x%08x - 0x%10x", strModule, &dwBegin, &dwEnd ) == 3 )
{
Trim( strModule );
//dwBegin &= 0x00ffffff;
//dwEnd &= 0x00ffffff;
strcpy( arrModules[nModules].strModuleName, strModule );
arrModules[nModules].dwBeginAddr = dwBegin;
arrModules[nModules].dwEndAddr = dwEnd;
arrModules[nModules].bLoaded = FALSE;
CHAR strModPath[MAX_PATH];
strcpy( strModPath, strModule );
if ( !Exist( strModPath ) )
{
strcpy( strModPath, "drivers\\default\\" );
strcat( strModPath, strModule );
}
if ( !Exist( strModPath ) )
{
strcpy( strModPath, "..\\" );
strcat( strModPath, strModule );
}
if ( !Exist( strModPath ) )
{
strcpy( strModPath, "..\\drivers\\default\\" );
strcat( strModPath, strModule );
}
if ( !Exist( strModPath ) )
{
nModules++;
continue;
}
if (! SymLoadModule64( hProcess, 0, strModPath, strModule,
dwBegin, dwEnd - dwBegin ) )
{
DbgPrint( _T("SymLoadModule64 ('%s') failed!\n"), strModule);
} else
{
DbgPrint( _T("Module '%s' Loaded. "), strModule);
IMAGEHLP_MODULE64 moduleInfo = {0};
moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if ( SymGetModuleInfo64( hProcess, dwBegin, &moduleInfo ) )
{
if ( moduleInfo.SymType == SymPdb )
DbgPrint( _T("PDB(%s)"), moduleInfo.LoadedPdbName );
if ( moduleInfo.SymType == SymNone )
DbgPrint( _T("NONE") );
if ( moduleInfo.SymType == SymExport )
DbgPrint( _T("EXPORT") );
}
DbgPrint( _T("\n") );
arrModules[nModules].bLoaded = TRUE;
}
}
nModules++;
}
if ( ( strlen(strLine) == 54 || strlen(strLine) == 23 ) && strncmp(strLine, "Stack frame", 11) == 0 )
{
if ( !bFrame )
{
bFrame = TRUE;
DbgPrint( _T("\nStack:\n"));
}
DWORD dwFrame;
if ( sscanf( strLine, "Stack frame 0x%08x", &dwFrame ) == 1 )
{
//dwFrame &= 0x00ffffff;
DWORD64 dwDisplacement;
DbgPrint( _T("0x%08x> "), dwFrame );
BYTE bBank = (BYTE)(dwFrame >> 24);
SModuleInfo *pModule = NULL;
SModuleInfo *pModuleLoaded = NULL;
int nCollisions = 0;
for (int i=0; i<nModules; i++)
{
if ( dwFrame >= arrModules[i].dwBeginAddr &&
dwFrame < arrModules[i].dwEndAddr )
{
if ( arrModules[i].bLoaded )
pModuleLoaded = arrModules + i;
pModule = arrModules + i;
nCollisions++;
}
}
if ( bBank != 0 && !pModuleLoaded) // current app - aura.exe
{
for (int i=0; i<nModules; i++)
{
if ( dwFrame >= arrModules[i].dwBeginAddr &&
dwFrame < arrModules[i].dwEndAddr )
{
DbgPrint( _T("[%s]+0x%x "), arrModules[i].strModuleName, dwFrame - arrModules[i].dwBeginAddr );
}
}
} else
{
IMAGEHLP_MODULE64 moduleInfo = {0};
moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if ( SymGetModuleInfo64( hProcess, dwFrame, &moduleInfo ) )
DbgPrint( _T("[%s]\t "), moduleInfo.ImageName );
if ( !SymGetSymFromAddr64( hProcess, dwFrame, &dwDisplacement, pSym ) )
{
DbgPrint( _T("Unknown"));
} else
{
DbgPrint( _T("%s"), pSym->Name );
DWORD dwDisplacement;
if ( SymGetLineFromAddr64( hProcess, dwFrame, &dwDisplacement, &Line ) )
{
if ( Line.FileName || Line.LineNumber )
{
DbgPrint( _T(" (%s: %d)"), MAXLEN(Line.FileName, 40), Line.LineNumber );
}
}
}
}
DbgPrint( _T("\n"));
}
}
}
fclose(f);
} else
{
DbgPrint( _T("SymInitialize failed\n") );
return 1;
}
SymCleanup( hProcess );
IMPORTEND();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment