Leaked source code of windows server 2003
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.

336 lines
9.2 KiB

  1. #include <assert.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <memory.h>
  5. #include <nt.h>
  6. #include <ntrtl.h>
  7. #include <nturtl.h>
  8. #include <ctype.h>
  9. #include <stdio.h>
  10. #include <windows.h>
  11. #include "profiler.h"
  12. #include "view.h"
  13. #include "thread.h"
  14. #include "dump.h"
  15. #include "except.h"
  16. #include "memory.h"
  17. #include "clevel.h"
  18. #include "cap.h"
  19. extern BOOL g_bIsWin9X;
  20. CAPFILTER g_execFilter;
  21. pfnExContinue g_pfnExContinue = 0;
  22. BOOL
  23. HookUnchainableExceptionFilter(VOID)
  24. {
  25. BOOL bResult;
  26. pfnRtlAddVectoredExceptionHandler pfnAddExceptionHandler = 0;
  27. PVOID pvResult;
  28. HANDLE hTemp;
  29. DWORD dwExceptionHandler;
  30. DWORD dwResultSize;
  31. PVOID pAlternateHeap;
  32. //
  33. // If we're NT - try for the unchainable filter in ntdll
  34. //
  35. if (FALSE == g_bIsWin9X) {
  36. pfnAddExceptionHandler = (pfnRtlAddVectoredExceptionHandler)GetProcAddress(GetModuleHandleA("NTDLL.DLL"),
  37. "RtlAddVectoredExceptionHandler");
  38. if (0 == pfnAddExceptionHandler) {
  39. return FALSE;
  40. }
  41. pvResult = (*pfnAddExceptionHandler)(1,
  42. (PVOID)ExceptionFilter);
  43. if (0 == pvResult) {
  44. return FALSE;
  45. }
  46. }
  47. else {
  48. //
  49. // Set up exception handler
  50. //
  51. hTemp = CreateFileA(NAME_OF_EXCEPTION_VXD,
  52. 0,
  53. 0,
  54. 0,
  55. 0,
  56. FILE_FLAG_DELETE_ON_CLOSE,
  57. 0);
  58. if (INVALID_HANDLE_VALUE == hTemp) {
  59. return FALSE;
  60. }
  61. _asm mov dwExceptionHandler, offset Win9XExceptionDispatcher
  62. bResult = DeviceIoControl(hTemp,
  63. INSTALL_RING_3_HANDLER,
  64. &dwExceptionHandler,
  65. sizeof(DWORD),
  66. 0,
  67. 0,
  68. &dwResultSize,
  69. 0);
  70. if (FALSE == bResult) {
  71. return FALSE;
  72. }
  73. //
  74. // Get function pointer for ExContinue
  75. //
  76. g_pfnExContinue = (pfnExContinue)0xbff76702;
  77. }
  78. return TRUE;
  79. }
  80. LONG
  81. ExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
  82. {
  83. DWORD dwThreadId;
  84. DWORD dwCounter;
  85. BOOL bResult;
  86. LONG lRet;
  87. PCONTEXT pContext = ExceptionInfo->ContextRecord;
  88. PEXCEPTION_RECORD pRecord = ExceptionInfo->ExceptionRecord;
  89. PVIEWCHAIN pView = 0;
  90. PTHREADFAULT pThreadFault = 0;
  91. CHAR szBuffer[MAX_PATH];
  92. //
  93. // Retrieve thread data
  94. //
  95. dwThreadId = GetCurrentThreadId();
  96. pThreadFault = GetProfilerThreadData();
  97. if (0 == pThreadFault) {
  98. //
  99. // NT only code path
  100. //
  101. pThreadFault = AllocateProfilerThreadData();
  102. if (0 == pThreadFault) {
  103. //
  104. // This wasn't suppose to happen
  105. //
  106. ExitProcess(-1);
  107. }
  108. }
  109. //
  110. // Rehook the view
  111. //
  112. if (STATUS_SINGLE_STEP == pRecord->ExceptionCode) {
  113. //
  114. // Trace is used to map into call or jumps types we can't forward map
  115. //
  116. if (pThreadFault->dwPrevBP) {
  117. //
  118. // If we're a call - patch the return address so we can maintain call level
  119. //
  120. if (pThreadFault->prevBPType == Call) {
  121. //
  122. // Push the return level hook
  123. //
  124. bResult = PushCaller((PVOID)pThreadFault,
  125. (PVOID)pContext->Esp);
  126. if (FALSE == bResult) {
  127. //
  128. // Ooops
  129. //
  130. ExitProcess(-1);
  131. }
  132. }
  133. RestoreAddressFromView(pThreadFault->dwPrevBP,
  134. FALSE);
  135. if ((pThreadFault->prevBPType == Call) ||
  136. (pThreadFault->prevBPType == Jump)) {
  137. //
  138. // Profile this routine if it hasn't been mapped
  139. //
  140. pView = FindView((DWORD)pRecord->ExceptionAddress);
  141. if (0 == pView) {
  142. //
  143. // Add this address as a mapping breakpoint
  144. //
  145. pView = AddViewToMonitor((DWORD)pRecord->ExceptionAddress,
  146. Map);
  147. if (pView) {
  148. bResult = MapCode(pView);
  149. if (FALSE == bResult) {
  150. //
  151. // This is fatal
  152. //
  153. ExitProcess(-1);
  154. }
  155. }
  156. }
  157. }
  158. pThreadFault->dwPrevBP = 0;
  159. pThreadFault->prevBPType = None;
  160. return EXCEPTION_CONTINUE_EXECUTION;
  161. }
  162. //
  163. // Trace exception wasn't generated by us
  164. //
  165. sprintf(szBuffer, "Unhandled Trace %08X\r\n", (DWORD)pRecord->ExceptionAddress);
  166. WriteError(szBuffer);
  167. return EXCEPTION_CONTINUE_SEARCH;
  168. }
  169. //
  170. // Restore the view
  171. //
  172. if (STATUS_BREAKPOINT == pRecord->ExceptionCode) {
  173. //
  174. // Restore any BP that hasn't been restored
  175. //
  176. if (pThreadFault->dwPrevBP) {
  177. RestoreAddressFromView(pThreadFault->dwPrevBP,
  178. FALSE);
  179. if ((DWORD)pRecord->ExceptionAddress == pThreadFault->dwPrevBP) {
  180. pThreadFault->dwPrevBP = 0;
  181. pThreadFault->prevBPType = None;
  182. return EXCEPTION_CONTINUE_EXECUTION;
  183. }
  184. }
  185. /*
  186. //
  187. // Add address to the execution filter
  188. //
  189. bResult = AddToCap(&g_execFilter,
  190. (DWORD)pRecord->ExceptionAddress);
  191. if (FALSE == bResult) {
  192. //
  193. // This is fatal
  194. //
  195. ExitProcess(-1);
  196. }
  197. //
  198. // If we've hit iteration - disable this and the previous breakpoints
  199. //
  200. if (0 != g_execFilter.dwIterationLock) {
  201. for (dwCounter = 0; dwCounter < g_execFilter.dwRunLength; dwCounter++) {
  202. //
  203. // Replace the munged code
  204. //
  205. pView = RestoreAddressFromView(g_execFilter.dwArray[g_execFilter.dwCursor - dwCounter - 1],
  206. TRUE);
  207. //
  208. // Add runtime event to log
  209. //
  210. sprintf(szBuffer, "CAP'ed %08X\r\n", g_execFilter.dwArray[g_execFilter.dwCursor - dwCounter - 1]);
  211. AddToDump(szBuffer,
  212. strlen(szBuffer),
  213. FALSE);
  214. }
  215. //
  216. // Clear breakpoint monitor flags
  217. //
  218. pThreadFault->dwPrevBP = 0;
  219. pThreadFault->prevBPType = None;
  220. return EXCEPTION_CONTINUE_EXECUTION;
  221. }
  222. */
  223. //
  224. // Replace the munged code
  225. //
  226. pView = RestoreAddressFromView((DWORD)pRecord->ExceptionAddress,
  227. TRUE);
  228. if (pView) {
  229. //
  230. // See if we've mapped this address range in yet
  231. //
  232. if (FALSE == pView->bMapped) {
  233. //
  234. // See if this address is already mapped
  235. //
  236. bResult = MapCode(pView);
  237. if (FALSE == bResult) {
  238. //
  239. // This is fatal
  240. //
  241. ExitProcess(-1);
  242. }
  243. }
  244. //
  245. // Set the trace so the last bp can be rehooked (unless we just executed a map bp)
  246. //
  247. pContext->EFlags |= 0x00000100;
  248. pThreadFault->dwPrevBP = (DWORD)pRecord->ExceptionAddress;
  249. pThreadFault->prevBPType = pView->bpType;
  250. //
  251. // Add runtime event to log
  252. //
  253. if (pView->bpType != ThreadStart) {
  254. WriteExeFlow(dwThreadId,
  255. (DWORD)pRecord->ExceptionAddress,
  256. pThreadFault->dwCallLevel);
  257. }
  258. else {
  259. WriteThreadStart(dwThreadId,
  260. (DWORD)pRecord->ExceptionAddress);
  261. }
  262. return EXCEPTION_CONTINUE_EXECUTION;
  263. }
  264. //
  265. // BP exception wasn't generated by us
  266. //
  267. sprintf(szBuffer, "Unhandled BP %08X\r\n", (DWORD)pRecord->ExceptionAddress);
  268. WriteError(szBuffer);
  269. return EXCEPTION_CONTINUE_SEARCH;
  270. }
  271. //
  272. // Continue searching the chain
  273. //
  274. return EXCEPTION_CONTINUE_SEARCH;
  275. }
  276. VOID
  277. Win9XExceptionDispatcher(struct _EXCEPTION_POINTERS *ExceptionInfo)
  278. {
  279. LONG lResult;
  280. //
  281. // Call exception handler
  282. //
  283. lResult = ExceptionFilter(ExceptionInfo);
  284. if (lResult != EXCEPTION_CONTINUE_EXECUTION) {
  285. //
  286. // Fault not handled - page fault will terminate app
  287. //
  288. return;
  289. }
  290. //
  291. // Set the context results
  292. //
  293. SET_CONTEXT();
  294. //
  295. // This code path is never executed (unless the above call fails)
  296. //
  297. return;
  298. }