Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
12 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. wamxcf.cxx
  5. Abstract:
  6. WAM Exception Filter and stack walking code from MTS
  7. Author:
  8. Andrei Kozlov ( AKozlov ) 23-Sep-98
  9. Environment:
  10. User Mode - Win32
  11. Project:
  12. WAM DLL
  13. --*/
  14. /************************************************************
  15. * Include Headers
  16. ************************************************************/
  17. # include <isapip.hxx>
  18. #include <imagehlp.h>
  19. # include "wamxinfo.hxx"
  20. # include "WReqCore.hxx"
  21. # include "setable.hxx"
  22. # include "gip.h"
  23. # include "WamW3.hxx"
  24. // MIDL-generated
  25. # include "iwr.h"
  26. // ===================================================================
  27. // Stack trace classes by Don McCrady of MTS
  28. class Symbol {
  29. friend class StackWalker;
  30. private:
  31. Symbol(const char* moduleName, const char* symbolName, UINT_PTR displacement);
  32. void Append(Symbol*);
  33. public:
  34. ~Symbol();
  35. const char* moduleName() const { return _moduleName; }
  36. const char* symbolName() const { return _symbolName; }
  37. UINT_PTR displacement() const { return _displacement; }
  38. void AppendDisplacement(char * sz)
  39. {
  40. char szDisp[16];
  41. wsprintfA(szDisp, " + 0x%X", _displacement);
  42. lstrcatA(sz, szDisp);
  43. }
  44. Symbol* next() const { return _next; }
  45. private:
  46. char* _moduleName;
  47. char* _symbolName;
  48. UINT_PTR _displacement;
  49. Symbol* _next;
  50. };
  51. class StackWalker {
  52. public:
  53. StackWalker(HANDLE hProcess);
  54. ~StackWalker();
  55. Symbol* ResolveAddress(UINT_PTR addr);
  56. Symbol* CreateStackTrace(CONTEXT*);
  57. BOOL GetCallStack(Symbol * symbol, int nChars, char * sz);
  58. int GetCallStackSize(Symbol* symbol);
  59. private:
  60. static UINT_PTR __stdcall GetModuleBase(HANDLE hProcess, UINT_PTR address);
  61. static UINT_PTR LoadModule(HANDLE hProcess, UINT_PTR address);
  62. private:
  63. typedef BOOL (__stdcall *SymGetModuleInfoFunc)(HANDLE hProcess,
  64. UINT_PTR dwAddr,
  65. PIMAGEHLP_MODULE ModuleInfo);
  66. typedef BOOL (__stdcall *SymGetSymFromAddrFunc)(HANDLE hProcess,
  67. UINT_PTR dwAddr,
  68. UINT_PTR * pdwDisplacement,
  69. PIMAGEHLP_SYMBOL Symbol);
  70. typedef UINT_PTR (__stdcall *SymLoadModuleFunc)(HANDLE hProcess,
  71. HANDLE hFile,
  72. PSTR ImageName,
  73. PSTR ModuleName,
  74. UINT_PTR BaseOfDll,
  75. UINT_PTR SizeOfDll);
  76. typedef BOOL (__stdcall *StackWalkFunc)(DWORD MachineType,
  77. HANDLE hProcess,
  78. HANDLE hThread,
  79. LPSTACKFRAME StackFrame,
  80. LPVOID ContextRecord,
  81. PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
  82. PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
  83. PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
  84. PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
  85. typedef BOOL (__stdcall *UndecorateSymbolNameFunc)(LPSTR DecName,
  86. LPSTR UnDecName,
  87. DWORD UnDecNameLength,
  88. DWORD Flags);
  89. private:
  90. HMODULE _imageHlpDLL;
  91. HANDLE _hProcess;
  92. EXCEPTION_POINTERS m_exceptionpts;
  93. static SymGetModuleInfoFunc _SymGetModuleInfo;
  94. static SymGetSymFromAddrFunc _SymGetSymFromAddr;
  95. static SymLoadModuleFunc _SymLoadModule;
  96. static StackWalkFunc _StackWalk;
  97. static UndecorateSymbolNameFunc _UndecorateSymbolName;
  98. static PFUNCTION_TABLE_ACCESS_ROUTINE _SymFunctionTableAccess;
  99. };
  100. // ======================================================================
  101. // Exception handling and stack traces
  102. // ======================================================================
  103. char * mystrdup(const char * sz)
  104. {
  105. int nLen = lstrlenA(sz) + 1;
  106. char * tmp = (char *)malloc(nLen);
  107. if (tmp)
  108. {
  109. lstrcpyA(tmp, sz);
  110. }
  111. return tmp;
  112. }
  113. StackWalker::SymGetModuleInfoFunc StackWalker::_SymGetModuleInfo;
  114. StackWalker::SymGetSymFromAddrFunc StackWalker::_SymGetSymFromAddr;
  115. StackWalker::SymLoadModuleFunc StackWalker::_SymLoadModule;
  116. StackWalker::StackWalkFunc StackWalker::_StackWalk;
  117. StackWalker::UndecorateSymbolNameFunc StackWalker::_UndecorateSymbolName;
  118. PFUNCTION_TABLE_ACCESS_ROUTINE StackWalker::_SymFunctionTableAccess;
  119. StackWalker::StackWalker(HANDLE hProcess)
  120. : _imageHlpDLL(NULL),
  121. _hProcess(hProcess)
  122. {
  123. _imageHlpDLL = LoadLibrary("imagehlp.dll");
  124. if (_imageHlpDLL != NULL) {
  125. // Get commonly used Sym* functions.
  126. if (_StackWalk == NULL) {
  127. // If one of them are null, assume
  128. // they all are. Benign race here.
  129. _StackWalk = (StackWalkFunc)GetProcAddress(_imageHlpDLL, "StackWalk");
  130. if (_StackWalk == NULL)
  131. return;
  132. _SymGetModuleInfo = (SymGetModuleInfoFunc)GetProcAddress(_imageHlpDLL,
  133. "SymGetModuleInfo");
  134. if (_SymGetModuleInfo == NULL)
  135. return;
  136. _SymGetSymFromAddr = (SymGetSymFromAddrFunc)GetProcAddress(_imageHlpDLL,
  137. "SymGetSymFromAddr");
  138. if (_SymGetSymFromAddr == NULL)
  139. return;
  140. _SymLoadModule = (SymLoadModuleFunc)GetProcAddress(_imageHlpDLL,
  141. "SymLoadModule");
  142. if (_SymLoadModule == NULL)
  143. return;
  144. _UndecorateSymbolName = (UndecorateSymbolNameFunc)GetProcAddress(_imageHlpDLL,
  145. "UnDecorateSymbolName");
  146. if (_UndecorateSymbolName == NULL)
  147. return;
  148. _SymFunctionTableAccess = (PFUNCTION_TABLE_ACCESS_ROUTINE)GetProcAddress(_imageHlpDLL,
  149. "SymFunctionTableAccess");
  150. if (_SymFunctionTableAccess == NULL)
  151. return;
  152. }
  153. // Sym* functions that we're only going to use locally.
  154. typedef BOOL (__stdcall *SymInitializeFunc)(HANDLE hProcess,
  155. LPSTR path,
  156. BOOL invadeProcess);
  157. typedef DWORD (__stdcall *SymSetOptionsFunc)(DWORD);
  158. SymInitializeFunc SymInitialize = (SymInitializeFunc)GetProcAddress(_imageHlpDLL,
  159. "SymInitialize");
  160. if (SymInitialize == NULL)
  161. return;
  162. SymSetOptionsFunc SymSetOptions = (SymSetOptionsFunc)GetProcAddress(_imageHlpDLL,
  163. "SymSetOptions");
  164. if (SymSetOptions == NULL)
  165. return;
  166. if (SymInitialize(hProcess, NULL, FALSE))
  167. SymSetOptions(0);
  168. }
  169. }
  170. StackWalker::~StackWalker() {
  171. if (_imageHlpDLL != NULL) {
  172. typedef BOOL (__stdcall *SymCleanupFunc)(HANDLE hProcess);
  173. SymCleanupFunc SymCleanup = (SymCleanupFunc)GetProcAddress(_imageHlpDLL,
  174. "SymCleanup");
  175. if (SymCleanup != NULL)
  176. SymCleanup(_hProcess);
  177. FreeLibrary(_imageHlpDLL);
  178. }
  179. }
  180. UINT_PTR StackWalker::LoadModule(HANDLE hProcess, UINT_PTR address) {
  181. MEMORY_BASIC_INFORMATION mbi;
  182. if (VirtualQueryEx(hProcess, (void*)address, &mbi, sizeof mbi)) {
  183. if (mbi.Type & MEM_IMAGE) {
  184. char module[MAX_PATH];
  185. DWORD cch = GetModuleFileNameA((HINSTANCE)mbi.AllocationBase,
  186. module,
  187. MAX_PATH);
  188. // Ignore the return code since we can't do anything with it.
  189. (void)_SymLoadModule(hProcess,
  190. NULL,
  191. ((cch) ? module : NULL),
  192. NULL,
  193. (ULONG_PTR)mbi.AllocationBase,
  194. 0);
  195. return (UINT_PTR)mbi.AllocationBase;
  196. }
  197. }
  198. return 0;
  199. }
  200. Symbol* StackWalker::ResolveAddress(UINT_PTR addr) {
  201. if (_imageHlpDLL == NULL)
  202. return NULL;
  203. // Find out what module the address lies in.
  204. char* module = NULL;
  205. IMAGEHLP_MODULE moduleInfo;
  206. moduleInfo.SizeOfStruct = sizeof moduleInfo;
  207. if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo)) {
  208. module = moduleInfo.ModuleName;
  209. }
  210. else {
  211. // First attempt failed, load the module info.
  212. LoadModule(_hProcess, addr);
  213. if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo))
  214. module = moduleInfo.ModuleName;
  215. }
  216. char* symbolName = NULL;
  217. char undecoratedName[512];
  218. IMAGEHLP_SYMBOL* symbolInfo = (IMAGEHLP_SYMBOL*)_alloca(sizeof(IMAGEHLP_SYMBOL) + 512);
  219. symbolInfo->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL) + 512;
  220. symbolInfo->MaxNameLength = 512;
  221. UINT_PTR displacement = 0;
  222. if (_SymGetSymFromAddr(_hProcess, addr, &displacement, symbolInfo)) {
  223. DWORD flags = UNDNAME_NO_MS_KEYWORDS
  224. | UNDNAME_NO_ACCESS_SPECIFIERS
  225. | UNDNAME_NO_FUNCTION_RETURNS
  226. | UNDNAME_NO_MEMBER_TYPE;
  227. if (_UndecorateSymbolName(symbolInfo->Name, undecoratedName, 512, flags))
  228. symbolName = undecoratedName;
  229. else
  230. symbolName = symbolInfo->Name;
  231. }
  232. else {
  233. displacement = addr - moduleInfo.BaseOfImage;
  234. }
  235. return new Symbol(module, symbolName, displacement);
  236. }
  237. UINT_PTR __stdcall StackWalker::GetModuleBase(HANDLE hProcess, UINT_PTR address) {
  238. IMAGEHLP_MODULE moduleInfo;
  239. moduleInfo.SizeOfStruct = sizeof moduleInfo;
  240. if (_SymGetModuleInfo(hProcess, address, &moduleInfo))
  241. return moduleInfo.BaseOfImage;
  242. else
  243. return LoadModule(hProcess, address);
  244. }
  245. Symbol* StackWalker::CreateStackTrace(CONTEXT* context) {
  246. if (_imageHlpDLL == NULL)
  247. return NULL;
  248. HANDLE hThread = GetCurrentThread();
  249. DWORD dwMachineType;
  250. STACKFRAME frame = {0};
  251. frame.AddrPC.Mode = AddrModeFlat;
  252. #if defined(_M_IX86)
  253. dwMachineType = IMAGE_FILE_MACHINE_I386;
  254. frame.AddrPC.Offset = context->Eip; // Program Counter
  255. frame.AddrStack.Offset = context->Esp; // Stack Pointer
  256. frame.AddrStack.Mode = AddrModeFlat;
  257. frame.AddrFrame.Offset = context->Ebp; // Frame Pointer
  258. #elif defined(_M_AMD64)
  259. dwMachineType = IMAGE_FILE_MACHINE_AMD64;
  260. frame.AddrPC.Offset = context->Rip; // Program Counter
  261. #elif defined(_M_IA64)
  262. dwMachineType = IMAGE_FILE_MACHINE_IA64;
  263. frame.AddrPC.Offset = CONTEXT_TO_PROGRAM_COUNTER(context);
  264. #elif
  265. #error("Unknown Target Machine");
  266. #endif
  267. // Walk the stack...
  268. Symbol* prev = NULL;
  269. Symbol* head = NULL;
  270. for (;;) {
  271. if (!_StackWalk(dwMachineType,
  272. _hProcess,
  273. hThread,
  274. &frame,
  275. &context,
  276. NULL,
  277. (PFUNCTION_TABLE_ACCESS_ROUTINE)_SymFunctionTableAccess,
  278. (PGET_MODULE_BASE_ROUTINE)GetModuleBase,
  279. NULL))
  280. break;
  281. if (frame.AddrPC.Offset == 0)
  282. break;
  283. Symbol* sym = ResolveAddress(frame.AddrPC.Offset);
  284. if (sym == NULL)
  285. break;
  286. // Append this symbol to the previous one, if any.
  287. if (prev == NULL) {
  288. prev = sym;
  289. head = sym;
  290. }
  291. else {
  292. prev->Append(sym);
  293. prev = sym;
  294. }
  295. }
  296. return head;
  297. }
  298. int StackWalker::GetCallStackSize(Symbol* symbol)
  299. {
  300. int nSize = 2; // Start with a "\r\n".
  301. const char* module = NULL;
  302. const char* symbolName = NULL;
  303. Symbol * sym = symbol;
  304. while (sym != NULL)
  305. {
  306. module = sym->moduleName();
  307. symbolName = sym->symbolName();
  308. nSize += lstrlenA(module);
  309. nSize += lstrlenA(symbolName);
  310. nSize += 32; // displacement, spaces, etc.
  311. sym = sym -> next();
  312. }
  313. return nSize;
  314. }
  315. BOOL StackWalker::GetCallStack(Symbol * symbol, int nChars, char * sz)
  316. {
  317. if (!symbol || !nChars)
  318. return FALSE;
  319. Symbol* sym = symbol;
  320. const char* module = NULL;
  321. const char* symbolName = NULL;
  322. ZeroMemory(sz, nChars);
  323. lstrcpy(sz, "\r\n"); // Start with a CR-LF.
  324. Symbol* tmp = NULL;
  325. while (sym != NULL)
  326. {
  327. module = sym->moduleName();
  328. symbolName = sym->symbolName();
  329. if (module != NULL)
  330. {
  331. strcat(sz, module);
  332. if (symbolName != NULL)
  333. strcat(sz, "!");
  334. }
  335. if (symbolName != NULL)
  336. strcat(sz, symbolName);
  337. sym->AppendDisplacement(sz);
  338. lstrcat(sz, "\r\n");
  339. tmp = sym;
  340. sym = sym->next();
  341. delete tmp;
  342. }
  343. return TRUE;
  344. }
  345. Symbol::Symbol(const char* moduleName, const char* symbolName, UINT_PTR displacement)
  346. : _moduleName(NULL),
  347. _symbolName(NULL),
  348. _displacement(displacement),
  349. _next(NULL)
  350. {
  351. if (moduleName != NULL)
  352. _moduleName = mystrdup(moduleName);
  353. if (symbolName != NULL)
  354. _symbolName = mystrdup(symbolName);
  355. }
  356. Symbol::~Symbol() {
  357. free(_moduleName);
  358. free(_symbolName);
  359. }
  360. void Symbol::Append(Symbol* sym) {
  361. _next = sym;
  362. }
  363. //
  364. // WAM Exception Filter -- walk the stack and log event
  365. //
  366. DWORD WAMExceptionFilter(
  367. EXCEPTION_POINTERS *xp,
  368. DWORD dwEventId,
  369. WAM_EXEC_INFO *pWamExecInfo
  370. )
  371. {
  372. CHAR * pszStack = NULL;
  373. //
  374. // Don't handle breakpoints
  375. //
  376. if (xp->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
  377. return EXCEPTION_CONTINUE_SEARCH;
  378. StackWalker walker( GetCurrentProcess() );
  379. Symbol* symbol = walker.CreateStackTrace( xp->ContextRecord );
  380. if( symbol ) {
  381. if (symbol != NULL) {
  382. int stackBufLen = walker.GetCallStackSize(symbol);
  383. pszStack = (TCHAR*)_alloca(stackBufLen * sizeof pszStack[0]);
  384. walker.GetCallStack(symbol, stackBufLen, pszStack);
  385. }
  386. }
  387. pWamExecInfo->LogEvent( dwEventId, (unsigned char *) pszStack );
  388. return EXCEPTION_EXECUTE_HANDLER;
  389. }