windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/wam/object/wamxcf.cxx
2020-09-26 16:20:57 +08:00

486 lines
12 KiB
C++

/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name :
wamxcf.cxx
Abstract:
WAM Exception Filter and stack walking code from MTS
Author:
Andrei Kozlov ( AKozlov ) 23-Sep-98
Environment:
User Mode - Win32
Project:
WAM DLL
--*/
/************************************************************
* Include Headers
************************************************************/
# include <isapip.hxx>
#include <imagehlp.h>
# include "wamxinfo.hxx"
# include "WReqCore.hxx"
# include "setable.hxx"
# include "gip.h"
# include "WamW3.hxx"
// MIDL-generated
# include "iwr.h"
// ===================================================================
// Stack trace classes by Don McCrady of MTS
class Symbol {
friend class StackWalker;
private:
Symbol(const char* moduleName, const char* symbolName, UINT_PTR displacement);
void Append(Symbol*);
public:
~Symbol();
const char* moduleName() const { return _moduleName; }
const char* symbolName() const { return _symbolName; }
UINT_PTR displacement() const { return _displacement; }
void AppendDisplacement(char * sz)
{
char szDisp[16];
wsprintfA(szDisp, " + 0x%X", _displacement);
lstrcatA(sz, szDisp);
}
Symbol* next() const { return _next; }
private:
char* _moduleName;
char* _symbolName;
UINT_PTR _displacement;
Symbol* _next;
};
class StackWalker {
public:
StackWalker(HANDLE hProcess);
~StackWalker();
Symbol* ResolveAddress(UINT_PTR addr);
Symbol* CreateStackTrace(CONTEXT*);
BOOL GetCallStack(Symbol * symbol, int nChars, char * sz);
int GetCallStackSize(Symbol* symbol);
private:
static UINT_PTR __stdcall GetModuleBase(HANDLE hProcess, UINT_PTR address);
static UINT_PTR LoadModule(HANDLE hProcess, UINT_PTR address);
private:
typedef BOOL (__stdcall *SymGetModuleInfoFunc)(HANDLE hProcess,
UINT_PTR dwAddr,
PIMAGEHLP_MODULE ModuleInfo);
typedef BOOL (__stdcall *SymGetSymFromAddrFunc)(HANDLE hProcess,
UINT_PTR dwAddr,
UINT_PTR * pdwDisplacement,
PIMAGEHLP_SYMBOL Symbol);
typedef UINT_PTR (__stdcall *SymLoadModuleFunc)(HANDLE hProcess,
HANDLE hFile,
PSTR ImageName,
PSTR ModuleName,
UINT_PTR BaseOfDll,
UINT_PTR SizeOfDll);
typedef BOOL (__stdcall *StackWalkFunc)(DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME StackFrame,
LPVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
typedef BOOL (__stdcall *UndecorateSymbolNameFunc)(LPSTR DecName,
LPSTR UnDecName,
DWORD UnDecNameLength,
DWORD Flags);
private:
HMODULE _imageHlpDLL;
HANDLE _hProcess;
EXCEPTION_POINTERS m_exceptionpts;
static SymGetModuleInfoFunc _SymGetModuleInfo;
static SymGetSymFromAddrFunc _SymGetSymFromAddr;
static SymLoadModuleFunc _SymLoadModule;
static StackWalkFunc _StackWalk;
static UndecorateSymbolNameFunc _UndecorateSymbolName;
static PFUNCTION_TABLE_ACCESS_ROUTINE _SymFunctionTableAccess;
};
// ======================================================================
// Exception handling and stack traces
// ======================================================================
char * mystrdup(const char * sz)
{
int nLen = lstrlenA(sz) + 1;
char * tmp = (char *)malloc(nLen);
if (tmp)
{
lstrcpyA(tmp, sz);
}
return tmp;
}
StackWalker::SymGetModuleInfoFunc StackWalker::_SymGetModuleInfo;
StackWalker::SymGetSymFromAddrFunc StackWalker::_SymGetSymFromAddr;
StackWalker::SymLoadModuleFunc StackWalker::_SymLoadModule;
StackWalker::StackWalkFunc StackWalker::_StackWalk;
StackWalker::UndecorateSymbolNameFunc StackWalker::_UndecorateSymbolName;
PFUNCTION_TABLE_ACCESS_ROUTINE StackWalker::_SymFunctionTableAccess;
StackWalker::StackWalker(HANDLE hProcess)
: _imageHlpDLL(NULL),
_hProcess(hProcess)
{
_imageHlpDLL = LoadLibrary("imagehlp.dll");
if (_imageHlpDLL != NULL) {
// Get commonly used Sym* functions.
if (_StackWalk == NULL) {
// If one of them are null, assume
// they all are. Benign race here.
_StackWalk = (StackWalkFunc)GetProcAddress(_imageHlpDLL, "StackWalk");
if (_StackWalk == NULL)
return;
_SymGetModuleInfo = (SymGetModuleInfoFunc)GetProcAddress(_imageHlpDLL,
"SymGetModuleInfo");
if (_SymGetModuleInfo == NULL)
return;
_SymGetSymFromAddr = (SymGetSymFromAddrFunc)GetProcAddress(_imageHlpDLL,
"SymGetSymFromAddr");
if (_SymGetSymFromAddr == NULL)
return;
_SymLoadModule = (SymLoadModuleFunc)GetProcAddress(_imageHlpDLL,
"SymLoadModule");
if (_SymLoadModule == NULL)
return;
_UndecorateSymbolName = (UndecorateSymbolNameFunc)GetProcAddress(_imageHlpDLL,
"UnDecorateSymbolName");
if (_UndecorateSymbolName == NULL)
return;
_SymFunctionTableAccess = (PFUNCTION_TABLE_ACCESS_ROUTINE)GetProcAddress(_imageHlpDLL,
"SymFunctionTableAccess");
if (_SymFunctionTableAccess == NULL)
return;
}
// Sym* functions that we're only going to use locally.
typedef BOOL (__stdcall *SymInitializeFunc)(HANDLE hProcess,
LPSTR path,
BOOL invadeProcess);
typedef DWORD (__stdcall *SymSetOptionsFunc)(DWORD);
SymInitializeFunc SymInitialize = (SymInitializeFunc)GetProcAddress(_imageHlpDLL,
"SymInitialize");
if (SymInitialize == NULL)
return;
SymSetOptionsFunc SymSetOptions = (SymSetOptionsFunc)GetProcAddress(_imageHlpDLL,
"SymSetOptions");
if (SymSetOptions == NULL)
return;
if (SymInitialize(hProcess, NULL, FALSE))
SymSetOptions(0);
}
}
StackWalker::~StackWalker() {
if (_imageHlpDLL != NULL) {
typedef BOOL (__stdcall *SymCleanupFunc)(HANDLE hProcess);
SymCleanupFunc SymCleanup = (SymCleanupFunc)GetProcAddress(_imageHlpDLL,
"SymCleanup");
if (SymCleanup != NULL)
SymCleanup(_hProcess);
FreeLibrary(_imageHlpDLL);
}
}
UINT_PTR StackWalker::LoadModule(HANDLE hProcess, UINT_PTR address) {
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQueryEx(hProcess, (void*)address, &mbi, sizeof mbi)) {
if (mbi.Type & MEM_IMAGE) {
char module[MAX_PATH];
DWORD cch = GetModuleFileNameA((HINSTANCE)mbi.AllocationBase,
module,
MAX_PATH);
// Ignore the return code since we can't do anything with it.
(void)_SymLoadModule(hProcess,
NULL,
((cch) ? module : NULL),
NULL,
(ULONG_PTR)mbi.AllocationBase,
0);
return (UINT_PTR)mbi.AllocationBase;
}
}
return 0;
}
Symbol* StackWalker::ResolveAddress(UINT_PTR addr) {
if (_imageHlpDLL == NULL)
return NULL;
// Find out what module the address lies in.
char* module = NULL;
IMAGEHLP_MODULE moduleInfo;
moduleInfo.SizeOfStruct = sizeof moduleInfo;
if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo)) {
module = moduleInfo.ModuleName;
}
else {
// First attempt failed, load the module info.
LoadModule(_hProcess, addr);
if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo))
module = moduleInfo.ModuleName;
}
char* symbolName = NULL;
char undecoratedName[512];
IMAGEHLP_SYMBOL* symbolInfo = (IMAGEHLP_SYMBOL*)_alloca(sizeof(IMAGEHLP_SYMBOL) + 512);
symbolInfo->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL) + 512;
symbolInfo->MaxNameLength = 512;
UINT_PTR displacement = 0;
if (_SymGetSymFromAddr(_hProcess, addr, &displacement, symbolInfo)) {
DWORD flags = UNDNAME_NO_MS_KEYWORDS
| UNDNAME_NO_ACCESS_SPECIFIERS
| UNDNAME_NO_FUNCTION_RETURNS
| UNDNAME_NO_MEMBER_TYPE;
if (_UndecorateSymbolName(symbolInfo->Name, undecoratedName, 512, flags))
symbolName = undecoratedName;
else
symbolName = symbolInfo->Name;
}
else {
displacement = addr - moduleInfo.BaseOfImage;
}
return new Symbol(module, symbolName, displacement);
}
UINT_PTR __stdcall StackWalker::GetModuleBase(HANDLE hProcess, UINT_PTR address) {
IMAGEHLP_MODULE moduleInfo;
moduleInfo.SizeOfStruct = sizeof moduleInfo;
if (_SymGetModuleInfo(hProcess, address, &moduleInfo))
return moduleInfo.BaseOfImage;
else
return LoadModule(hProcess, address);
}
Symbol* StackWalker::CreateStackTrace(CONTEXT* context) {
if (_imageHlpDLL == NULL)
return NULL;
HANDLE hThread = GetCurrentThread();
DWORD dwMachineType;
STACKFRAME frame = {0};
frame.AddrPC.Mode = AddrModeFlat;
#if defined(_M_IX86)
dwMachineType = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = context->Eip; // Program Counter
frame.AddrStack.Offset = context->Esp; // Stack Pointer
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->Ebp; // Frame Pointer
#elif defined(_M_AMD64)
dwMachineType = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = context->Rip; // Program Counter
#elif defined(_M_IA64)
dwMachineType = IMAGE_FILE_MACHINE_IA64;
frame.AddrPC.Offset = CONTEXT_TO_PROGRAM_COUNTER(context);
#elif
#error("Unknown Target Machine");
#endif
// Walk the stack...
Symbol* prev = NULL;
Symbol* head = NULL;
for (;;) {
if (!_StackWalk(dwMachineType,
_hProcess,
hThread,
&frame,
&context,
NULL,
(PFUNCTION_TABLE_ACCESS_ROUTINE)_SymFunctionTableAccess,
(PGET_MODULE_BASE_ROUTINE)GetModuleBase,
NULL))
break;
if (frame.AddrPC.Offset == 0)
break;
Symbol* sym = ResolveAddress(frame.AddrPC.Offset);
if (sym == NULL)
break;
// Append this symbol to the previous one, if any.
if (prev == NULL) {
prev = sym;
head = sym;
}
else {
prev->Append(sym);
prev = sym;
}
}
return head;
}
int StackWalker::GetCallStackSize(Symbol* symbol)
{
int nSize = 2; // Start with a "\r\n".
const char* module = NULL;
const char* symbolName = NULL;
Symbol * sym = symbol;
while (sym != NULL)
{
module = sym->moduleName();
symbolName = sym->symbolName();
nSize += lstrlenA(module);
nSize += lstrlenA(symbolName);
nSize += 32; // displacement, spaces, etc.
sym = sym -> next();
}
return nSize;
}
BOOL StackWalker::GetCallStack(Symbol * symbol, int nChars, char * sz)
{
if (!symbol || !nChars)
return FALSE;
Symbol* sym = symbol;
const char* module = NULL;
const char* symbolName = NULL;
ZeroMemory(sz, nChars);
lstrcpy(sz, "\r\n"); // Start with a CR-LF.
Symbol* tmp = NULL;
while (sym != NULL)
{
module = sym->moduleName();
symbolName = sym->symbolName();
if (module != NULL)
{
strcat(sz, module);
if (symbolName != NULL)
strcat(sz, "!");
}
if (symbolName != NULL)
strcat(sz, symbolName);
sym->AppendDisplacement(sz);
lstrcat(sz, "\r\n");
tmp = sym;
sym = sym->next();
delete tmp;
}
return TRUE;
}
Symbol::Symbol(const char* moduleName, const char* symbolName, UINT_PTR displacement)
: _moduleName(NULL),
_symbolName(NULL),
_displacement(displacement),
_next(NULL)
{
if (moduleName != NULL)
_moduleName = mystrdup(moduleName);
if (symbolName != NULL)
_symbolName = mystrdup(symbolName);
}
Symbol::~Symbol() {
free(_moduleName);
free(_symbolName);
}
void Symbol::Append(Symbol* sym) {
_next = sym;
}
//
// WAM Exception Filter -- walk the stack and log event
//
DWORD WAMExceptionFilter(
EXCEPTION_POINTERS *xp,
DWORD dwEventId,
WAM_EXEC_INFO *pWamExecInfo
)
{
CHAR * pszStack = NULL;
//
// Don't handle breakpoints
//
if (xp->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
return EXCEPTION_CONTINUE_SEARCH;
StackWalker walker( GetCurrentProcess() );
Symbol* symbol = walker.CreateStackTrace( xp->ContextRecord );
if( symbol ) {
if (symbol != NULL) {
int stackBufLen = walker.GetCallStackSize(symbol);
pszStack = (TCHAR*)_alloca(stackBufLen * sizeof pszStack[0]);
walker.GetCallStack(symbol, stackBufLen, pszStack);
}
}
pWamExecInfo->LogEvent( dwEventId, (unsigned char *) pszStack );
return EXCEPTION_EXECUTE_HANDLER;
}