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.

910 lines
27 KiB

  1. /****************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dumprep.cpp
  5. Abstract:
  6. hang manager intermediate app
  7. *** IMPORTANT NOTE: this links with the single threaded CRT static lib. If
  8. it is changed to be multithreaded for some odd reason,
  9. then the sources file must be modified to link to
  10. libcmt.lib.
  11. Revision History:
  12. DerekM created 08/16/00
  13. ****************************************************************************/
  14. /////////////////////////////////////////////////////////////////////////////
  15. // tracing
  16. #ifdef THIS_FILE
  17. #undef THIS_FILE
  18. #endif
  19. static char __szTraceSourceFile[] = __FILE__;
  20. #define THIS_FILE __szTraceSourceFile
  21. #include "stdafx.h"
  22. #include "malloc.h"
  23. #include "faultrep.h"
  24. #include "pfrcfg.h"
  25. #include <shlwapi.h>
  26. #include <strsafe.h>
  27. enum EOp
  28. {
  29. eopNone = 0,
  30. eopHang,
  31. eopDump,
  32. eopEvent
  33. };
  34. enum ECheckType
  35. {
  36. ctNone = -1,
  37. ctKernel = 0,
  38. ctUser,
  39. ctShutdown,
  40. ctNumChecks
  41. };
  42. struct SCheckData
  43. {
  44. LPCWSTR wszRegPath;
  45. LPCWSTR wszRunVal;
  46. LPCWSTR wszEventName;
  47. LPCSTR szFnName;
  48. BOOL fUseData;
  49. BOOL fDelDump;
  50. };
  51. struct SQueuePruneData
  52. {
  53. LPWSTR wszVal;
  54. FILETIME ftFault;
  55. };
  56. char *eopStr[] =
  57. {
  58. "eopNone",
  59. "eopHang",
  60. "eopDump",
  61. "eopEvent"
  62. };
  63. //////////////////////////////////////////////////////////////////////////////
  64. // constants
  65. const char c_szKSFnName[] = "ReportEREventDW";
  66. const char c_szUserFnName[] = "ReportFaultFromQueue";
  67. SCheckData g_scd[ctNumChecks] =
  68. {
  69. { c_wszRKKrnl, c_wszRVKFC, c_wszMutKrnlName, c_szKSFnName, FALSE, FALSE },
  70. { c_wszRKUser, c_wszRVUFC, c_wszMutUserName, c_szUserFnName, TRUE, TRUE },
  71. { c_wszRKShut, c_wszRVSEC, c_wszMutShutName, c_szKSFnName, FALSE, FALSE },
  72. };
  73. #define EV_ACCESS_ALL GENERIC_ALL | STANDARD_RIGHTS_ALL
  74. #define EV_ACCESS_RS GENERIC_READ | SYNCHRONIZE
  75. #define pfn_VALONLY pfn_REPORTEREVENTDW
  76. #define pfn_VALDATA pfn_REPORTFAULTFROMQ
  77. //////////////////////////////////////////////////////////////////////////////
  78. // globals
  79. BOOL g_fDeleteReg = TRUE;
  80. //////////////////////////////////////////////////////////////////////////////
  81. // misc
  82. // **************************************************************************
  83. LONG __stdcall ExceptionTrap(_EXCEPTION_POINTERS *ExceptionInfo)
  84. {
  85. return EXCEPTION_EXECUTE_HANDLER;
  86. }
  87. // **************************************************************************
  88. HRESULT PruneQ(HKEY hkeyQ, DWORD cQSize, DWORD cMaxQSize, DWORD cchMaxVal,
  89. DWORD cbMaxData)
  90. {
  91. USE_TRACING("PruneQ");
  92. SQueuePruneData *pqpd = NULL;
  93. FILETIME ft;
  94. HRESULT hr = NOERROR;
  95. LPWSTR pwsz, pwszCurrent = NULL;
  96. DWORD cchVal, cbData, dwType, cToDel = 0, cInDelList = 0;
  97. DWORD i, iEntry, dw, cValid = 0;
  98. VALIDATEPARM(hr, (hkeyQ == NULL));
  99. if (FAILED(hr))
  100. goto done;
  101. if (cMaxQSize > cQSize)
  102. goto done;
  103. // don't need to do a +1 here (as in user faults) because we're not going
  104. // to add anything to the queue after this. This just ensures that we
  105. // don't report too many things
  106. cToDel = cQSize - cMaxQSize;
  107. // alloc the various buffers that we'll need:
  108. // the delete list
  109. // the current file we're working with
  110. // the data blob associated with the current file
  111. cbData = (sizeof(SQueuePruneData) + (cchMaxVal * sizeof(WCHAR))) * cToDel;
  112. pwszCurrent = (LPWSTR)MyAlloc(cchMaxVal * sizeof(WCHAR));
  113. pqpd = (SQueuePruneData *)MyAlloc(cbData);
  114. if (pwszCurrent == NULL || pqpd == NULL)
  115. {
  116. SetLastError(ERROR_OUTOFMEMORY);
  117. hr = E_OUTOFMEMORY;
  118. goto done;
  119. }
  120. // intiailize all the string pointers in the delete list
  121. pwsz = (LPWSTR)((BYTE *)pqpd + (sizeof(SQueuePruneData) * cToDel));
  122. for (i = 0; i < cToDel; i++)
  123. {
  124. pqpd[i].ftFault.dwHighDateTime = 0;
  125. pqpd[i].ftFault.dwLowDateTime = 0;
  126. pqpd[i].wszVal = pwsz;
  127. pqpd[i].wszVal[0] = L'\0';
  128. pwsz += cchMaxVal;
  129. }
  130. // ok, get a list of all the valid items and build an array in sorted order
  131. // so that we can easily pick off the top n items
  132. for(iEntry = 0; iEntry < cQSize; iEntry++)
  133. {
  134. cchVal = cchMaxVal;
  135. cbData = sizeof(ft);
  136. dw = RegEnumValueW(hkeyQ, iEntry, pwszCurrent, &cchVal, 0, &dwType,
  137. (PBYTE)&ft, &cbData);
  138. if (dw == ERROR_NO_MORE_ITEMS)
  139. break;
  140. else if (dw != ERROR_SUCCESS)
  141. continue;
  142. else if (dwType != REG_BINARY || cbData != sizeof(ft))
  143. {
  144. RegDeleteValueW(hkeyQ, pwszCurrent);
  145. continue;
  146. }
  147. for (i = 0; i < cInDelList; i++)
  148. {
  149. if ((ft.dwHighDateTime < pqpd[i].ftFault.dwHighDateTime) ||
  150. (ft.dwHighDateTime == pqpd[i].ftFault.dwHighDateTime &&
  151. ft.dwLowDateTime < pqpd[i].ftFault.dwLowDateTime))
  152. break;
  153. }
  154. // if it's in the middle of the current list, then we gotta move
  155. // stuff around
  156. if (cInDelList > 0 && i < cInDelList - 1)
  157. {
  158. LPWSTR pwszTemp = pqpd[cInDelList - 1].wszVal;
  159. MoveMemory(&pqpd[i], &pqpd[i + 1],
  160. (cInDelList - i) * sizeof(SQueuePruneData));
  161. pqpd[i].wszVal = pwszTemp;
  162. }
  163. if (i < cToDel)
  164. {
  165. // note that this copy is safe cuz each string slot is the same
  166. // size as the buffer pointed to by pwszCurrent and that buffer is
  167. // protected from overflow by the size we pass into
  168. // RegEnumValueW()
  169. StringCbCopyW(pqpd[i].wszVal, cchMaxVal * sizeof(WCHAR), pwszCurrent);
  170. pqpd[i].ftFault = ft;
  171. if (cInDelList < cToDel)
  172. cInDelList++;
  173. }
  174. cValid++;
  175. }
  176. // if there aren't enuf valid entries to warrant a purge, then don't purge
  177. if (cValid < cMaxQSize)
  178. goto done;
  179. cToDel = MyMin(cToDel, cValid - cMaxQSize + 1);
  180. // purge enuf entries that we go down to 1 below our max (since we have to
  181. // be adding 1 to get here- don't want that 1 to drive us over the limit
  182. for(i = 0; i < cToDel; i++)
  183. {
  184. if (pqpd[i].wszVal != NULL)
  185. RegDeleteValueW(hkeyQ, pqpd[i].wszVal);
  186. }
  187. done:
  188. if (pqpd != NULL)
  189. MyFree(pqpd);
  190. if (pwszCurrent != NULL)
  191. MyFree(pwszCurrent);
  192. return hr;
  193. }
  194. // **************************************************************************
  195. HRESULT CheckQSizeAndPrune(HKEY hkeyQ)
  196. {
  197. USE_TRACING("CheckQueueSizeAndPrune");
  198. CPFFaultClientCfg oCfg;
  199. HRESULT hr = NOERROR;
  200. DWORD cMaxQSize = 0, cDefMaxQSize = 10;
  201. DWORD cQSize, cchMaxVal, cbMaxData, dwType;
  202. DWORD cb, dw;
  203. HKEY hkey = NULL;
  204. VALIDATEPARM(hr, (hkeyQ == NULL));
  205. if (FAILED(hr))
  206. goto done;
  207. // read the policy settings for UI and reporting
  208. TESTHR(hr, oCfg.Read(eroPolicyRO));
  209. cMaxQSize = oCfg.get_MaxUserQueueSize();
  210. if (FAILED(hr))
  211. {
  212. cMaxQSize = cDefMaxQSize;
  213. hr = NOERROR;
  214. }
  215. else
  216. {
  217. // there are other ways of disabling these reporting modes, so don't
  218. // honor a like we would for user faults
  219. if (cMaxQSize == 0)
  220. cMaxQSize = 1;
  221. // -1 means there is no limit
  222. else if (cMaxQSize == (DWORD)-1)
  223. {
  224. hr = NOERROR;
  225. goto done;
  226. }
  227. else if (cMaxQSize > c_cMaxQueue)
  228. cMaxQSize = c_cMaxQueue;
  229. }
  230. __try
  231. {
  232. // determine what the Q size is.
  233. TESTERR(hr, RegQueryInfoKey(hkeyQ, NULL, NULL, NULL, NULL, NULL, NULL,
  234. &cQSize, &cchMaxVal, &cbMaxData, NULL, NULL));
  235. if (SUCCEEDED(hr) && (cQSize >= cMaxQSize))
  236. {
  237. cchMaxVal++;
  238. TESTHR(hr, PruneQ(hkeyQ, cQSize, cMaxQSize, cchMaxVal, cbMaxData));
  239. }
  240. else
  241. {
  242. hr = NOERROR;
  243. }
  244. }
  245. __except(EXCEPTION_EXECUTE_HANDLER)
  246. {
  247. }
  248. done:
  249. return hr;
  250. }
  251. // **************************************************************************
  252. void DeleteQueuedEvents(HKEY hkey, LPWSTR wszVal, DWORD cchMaxVal,
  253. ECheckType ct)
  254. {
  255. DWORD cchVal, dw;
  256. HKEY hkeyRun = NULL;
  257. HRESULT hr = NOERROR;
  258. USE_TRACING("DeleteQueuedEvents");
  259. VALIDATEPARM(hr, (hkey == NULL || wszVal == NULL));
  260. if (FAILED(hr))
  261. {
  262. SetLastError(ERROR_INVALID_PARAMETER);
  263. goto done;
  264. }
  265. for(;;)
  266. {
  267. cchVal = cchMaxVal;
  268. dw = RegEnumValueW(hkey, 0, wszVal, &cchVal, NULL, NULL,
  269. NULL, NULL);
  270. if (dw != ERROR_SUCCESS && dw != ERROR_NO_MORE_ITEMS)
  271. {
  272. SetLastError(dw);
  273. goto done;
  274. }
  275. if (dw == ERROR_NO_MORE_ITEMS)
  276. break;
  277. RegDeleteValueW(hkey, wszVal);
  278. if (ct == ctUser)
  279. DeleteFullAndTriageMiniDumps(wszVal);
  280. }
  281. // gotta delete our value out of the Run key so we don't run
  282. // unnecessarily again...
  283. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKRun, 0,
  284. KEY_ALL_ACCESS, &hkeyRun);
  285. if (dw != ERROR_SUCCESS)
  286. goto done;
  287. RegDeleteValueW(hkeyRun, g_scd[ct].wszRunVal);
  288. done:
  289. if (hkeyRun != NULL)
  290. RegCloseKey(hkeyRun);
  291. return;
  292. }
  293. // **************************************************************************
  294. void ReportEvents(HMODULE hmod, ECheckType ct)
  295. {
  296. CPFFaultClientCfg oCfg;
  297. EFaultRepRetVal frrv;
  298. pfn_VALONLY pfnVO = NULL;
  299. pfn_VALDATA pfnVD = NULL;
  300. EEventType eet = eetKernelFault;
  301. HRESULT hr = NOERROR;
  302. HANDLE hmut = NULL;
  303. LPWSTR wszVal = NULL;
  304. LPBYTE pbData = NULL, pbDataToUse = NULL;
  305. EEnDis eedReport, eedUI;
  306. DWORD cchVal = 0, cchMaxVal = 0, cbMaxData = 0, cVals = 0;
  307. DWORD dw, cbData = 0, *pcbData = NULL, iRegRead = 0;
  308. DWORD dwType;
  309. HKEY hkey;
  310. USE_TRACING("ReportEvents");
  311. VALIDATEPARM(hr, ((ct <= ctNone && ct >= ctNumChecks) || hmod == NULL));
  312. if (FAILED(hr))
  313. return;
  314. // assume hmod is valid cuz we do a check in wWinMain to make sure it is
  315. // before calling this fn
  316. if (g_scd[ct].fUseData)
  317. pfnVD = (pfn_VALDATA)GetProcAddress(hmod, g_scd[ct].szFnName);
  318. else
  319. pfnVO = (pfn_VALONLY)GetProcAddress(hmod, g_scd[ct].szFnName);
  320. VALIDATEPARM(hr, (pfnVD == NULL && pfnVO == NULL));
  321. if (FAILED(hr))
  322. return;
  323. // read the policy settings for UI and reporting
  324. TESTHR(hr, oCfg.Read(eroPolicyRO));
  325. if (FAILED(hr))
  326. return;
  327. eedReport = oCfg.get_DoReport();
  328. eedUI = oCfg.get_ShowUI();
  329. if (eedUI != eedEnabled && eedUI != eedDisabled &&
  330. eedUI != eedEnabledNoCheck)
  331. eedUI = eedEnabled;
  332. if (eedReport != eedEnabled && eedReport != eedDisabled)
  333. eedReport = eedEnabled;
  334. // only want one user at a time going thru this
  335. hmut = OpenMutexW(SYNCHRONIZE, FALSE, g_scd[ct].wszEventName);
  336. VALIDATEPARM(hr, (hmut == NULL));
  337. if (FAILED(hr))
  338. return;
  339. // the default value above is eetKernelFault, so only need to change if
  340. // it's a shutdown
  341. if (ct == ctShutdown)
  342. eet = eetShutdown;
  343. __try
  344. {
  345. __try
  346. {
  347. // give this wait five minutes. If the code doesn't complete by
  348. // then, then we're either held up by DW (which means an admin
  349. // aleady passed thru here) or something has barfed and is holding
  350. // the mutex.
  351. dw = WaitForSingleObject(hmut, 300000);
  352. if (dw != WAIT_OBJECT_0 && dw != WAIT_ABANDONED)
  353. __leave;
  354. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, g_scd[ct].wszRegPath, 0,
  355. KEY_ALL_ACCESS, &hkey);
  356. if (dw != ERROR_SUCCESS)
  357. __leave;
  358. // make sure we only have a fixed number of errors to report.
  359. if (ct == ctShutdown || ct == ctKernel)
  360. CheckQSizeAndPrune(hkey);
  361. // determine how big the valuename is & allocate a buffer for it
  362. dw = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL,
  363. &cVals, &cchMaxVal, &cbMaxData, NULL, NULL);
  364. if (dw != ERROR_SUCCESS || cVals == 0 || cchMaxVal == 0)
  365. __leave;
  366. cchMaxVal++;
  367. // get us some buffers to hold the data bits we're interested in...
  368. wszVal = (LPWSTR)MyAlloc(cchMaxVal * sizeof(WCHAR));
  369. if (wszVal == NULL)
  370. __leave;
  371. // if we're completely disabled, then nuke all the queued stuff
  372. // and bail
  373. if (eedUI == eedDisabled && eedReport == eedDisabled)
  374. {
  375. DeleteQueuedEvents(hkey, wszVal, cchMaxVal, ct);
  376. __leave;
  377. }
  378. if (g_scd[ct].fUseData)
  379. {
  380. pbData = (LPBYTE) MyAlloc(cbMaxData);
  381. if (pbData == NULL)
  382. __leave;
  383. pbDataToUse = pbData;
  384. pcbData = &cbData;
  385. }
  386. iRegRead = 0;
  387. do
  388. {
  389. HANDLE hFile = INVALID_HANDLE_VALUE;
  390. cchVal = cchMaxVal;
  391. cbData = cbMaxData;
  392. dw = RegEnumValueW(hkey, iRegRead, wszVal, &cchVal, NULL,
  393. &dwType, pbDataToUse, pcbData);
  394. if (dw != ERROR_SUCCESS && dw != ERROR_NO_MORE_ITEMS)
  395. __leave;
  396. if (dw == ERROR_NO_MORE_ITEMS)
  397. break;
  398. // make sure that the file exists
  399. hFile = CreateFileW(wszVal, GENERIC_READ,
  400. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  401. OPEN_EXISTING, 0, NULL);
  402. if (hFile == INVALID_HANDLE_VALUE)
  403. {
  404. BOOL fInc = TRUE;
  405. if (GetLastError() == ERROR_FILE_NOT_FOUND ||
  406. GetLastError() == ERROR_PATH_NOT_FOUND)
  407. {
  408. dw = RegDeleteValueW(hkey, wszVal);
  409. if (dw == ERROR_SUCCESS ||
  410. dw == ERROR_FILE_NOT_FOUND ||
  411. dw == ERROR_PATH_NOT_FOUND)
  412. fInc = FALSE;
  413. }
  414. if (fInc)
  415. iRegRead++;
  416. continue;
  417. }
  418. CloseHandle(hFile);
  419. hFile = INVALID_HANDLE_VALUE;
  420. if (g_scd[ct].fUseData)
  421. {
  422. // if the type isn't REG_BINARY, then someone wrote an
  423. // invalid blob to the registry. We have to ignore it.
  424. if (dwType == REG_BINARY)
  425. frrv = (*pfnVD)(wszVal, pbData, cbData);
  426. else
  427. {
  428. SetLastError(ERROR_INVALID_PARAMETER);
  429. frrv = frrvOk;
  430. }
  431. }
  432. else
  433. {
  434. frrv = (*pfnVO)(eet, wszVal, NULL);
  435. }
  436. // if the call succeeds (or the data we fed to it was invalid)
  437. // then nuke the reg key & dump file
  438. if (GetLastError() == ERROR_INVALID_PARAMETER ||
  439. (g_fDeleteReg && frrv == frrvOk))
  440. {
  441. dw = RegDeleteValueW(hkey, wszVal);
  442. if (dw != ERROR_SUCCESS && dw != ERROR_FILE_NOT_FOUND &&
  443. dw != ERROR_PATH_NOT_FOUND)
  444. {
  445. iRegRead++;
  446. continue;
  447. }
  448. if (g_scd[ct].fDelDump && g_fDeleteReg)
  449. DeleteFullAndTriageMiniDumps(wszVal);
  450. }
  451. #if 0
  452. // if we timed out, then clean up the reg key. If this is the
  453. // last report we're gonna make, also clean up the Run key
  454. else if (g_fDeleteReg && frrv == frrvErrTimeout)
  455. {
  456. RegDeleteValueW(hkey, wszVal);
  457. dw = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL,
  458. &cVals, NULL, NULL, NULL, NULL);
  459. if (dw != ERROR_SUCCESS || cVals > 0)
  460. __leave;
  461. else
  462. break;
  463. }
  464. #endif
  465. else
  466. {
  467. // don't delete the Run key if we got an error and didn't
  468. // delete the fault key
  469. if (frrv != frrvOk)
  470. __leave;
  471. }
  472. }
  473. while(1);
  474. RegCloseKey(hkey);
  475. hkey = NULL;
  476. // gotta delete our value out of the Run key so we don't run
  477. // unnecessarily again...
  478. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKRun, 0,
  479. KEY_ALL_ACCESS, &hkey);
  480. if (dw != ERROR_SUCCESS)
  481. __leave;
  482. RegDeleteValueW(hkey, g_scd[ct].wszRunVal);
  483. }
  484. __finally
  485. {
  486. }
  487. }
  488. __except(EXCEPTION_EXECUTE_HANDLER)
  489. {
  490. }
  491. if (hmut != NULL)
  492. {
  493. ReleaseMutex(hmut);
  494. CloseHandle(hmut);
  495. }
  496. if (hkey != NULL)
  497. RegCloseKey(hkey);
  498. if (pbData != NULL)
  499. MyFree(pbData);
  500. if (wszVal != NULL)
  501. MyFree(wszVal);
  502. }
  503. //////////////////////////////////////////////////////////////////////////////
  504. // wmain
  505. // **************************************************************************
  506. int __cdecl wmain(int argc, WCHAR **argv)
  507. {
  508. EFaultRepRetVal frrv = frrvErrNoDW;
  509. SMDumpOptions smdo, *psmdo = &smdo;
  510. ECheckType ct = ctNone;
  511. HMODULE hmod = NULL;
  512. HANDLE hevNotify = NULL, hproc = NULL, hmem = NULL;
  513. LPWSTR wszDump = NULL;
  514. WCHAR wszMod[MAX_PATH];
  515. WCHAR wszCmdLine[MAX_PATH];
  516. DWORD dwpid, dwtid;
  517. BOOL f64bit = FALSE;
  518. int i;
  519. EOp eop = eopNone;
  520. HRESULT hr = NOERROR;
  521. // we don't want to have any faults get trapped anywhere.
  522. SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_NOALIGNMENTFAULTEXCEPT |
  523. SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  524. SetUnhandledExceptionFilter(ExceptionTrap);
  525. INIT_TRACING
  526. USE_TRACING("DumpRep.wmain");
  527. VALIDATEPARM(hr, (argc < 2 || argc > 8));
  528. if (FAILED(hr))
  529. goto done;
  530. dwpid = _wtol(argv[1]);
  531. ZeroMemory(&smdo, sizeof(smdo));
  532. for (i = 2; i < argc; i++)
  533. {
  534. if (argv[i][0] != L'-')
  535. continue;
  536. switch(argv[i][1])
  537. {
  538. // debug flag to prevent deletion of reg entries
  539. case L'E':
  540. case L'e':
  541. #if defined(NO_WAY_DEBUG) || defined(NO_WAY__DEBUG)
  542. g_fDeleteReg = FALSE;
  543. #endif
  544. break;
  545. // user or kernel faults or shutdowns
  546. case L'K':
  547. case L'k':
  548. case L'U':
  549. case L'u':
  550. case L'S':
  551. case L's':
  552. if (eop != eopNone)
  553. goto done;
  554. eop = eopEvent;
  555. ErrorTrace(0, " eopEvent = %S", argv[i] );
  556. // to workaround the desktop hanging while all Run processes
  557. // do their thing, we spawn a another copy of ourselves and
  558. // immediately exit.
  559. if (argv[i][2] != L'G' && argv[i][2] != L'g')
  560. {
  561. PROCESS_INFORMATION pi;
  562. STARTUPINFOW si;
  563. PWCHAR pFileName;
  564. if (GetModuleFileNameW(NULL, wszMod, sizeofSTRW(wszMod)) == 0)
  565. {
  566. goto done;
  567. }
  568. // Now create commandline to be passed to CreateProcessW
  569. if (!(pFileName = wcschr(wszMod,L'\\')))
  570. {
  571. pFileName = wszMod;
  572. }
  573. StringCbCopyW(wszCmdLine, sizeof(wszCmdLine), pFileName);
  574. if (argv[i][1] == L'K' || argv[i][1] == L'k')
  575. StringCbCatW(wszCmdLine, sizeof(wszMod), L" 0 -KG");
  576. else if (argv[i][1] == L'U' || argv[i][1] == L'u')
  577. StringCbCatW(wszCmdLine, sizeof(wszMod), L" 0 -UG");
  578. else
  579. StringCbCatW(wszCmdLine, sizeof(wszMod), L" 0 -SG");
  580. ZeroMemory(&si, sizeof(si));
  581. si.cb = sizeof(si);
  582. ErrorTrace(0, " spawning \'%S\'", wszCmdLine );
  583. if (CreateProcessW(wszMod, wszCmdLine, NULL, NULL, FALSE, 0, NULL,
  584. NULL, &si, &pi))
  585. {
  586. CloseHandle(pi.hThread);
  587. CloseHandle(pi.hProcess);
  588. }
  589. goto done;
  590. }
  591. else
  592. {
  593. if (argv[i][1] == L'K' || argv[i][1] == L'k')
  594. ct = ctKernel;
  595. else if (argv[i][1] == L'U' || argv[i][1] == L'u')
  596. ct = ctUser;
  597. else
  598. ct = ctShutdown;
  599. }
  600. break;
  601. // hangs
  602. case L'H':
  603. case L'h':
  604. if (i + 1 >= argc || eop != eopNone)
  605. goto done;
  606. eop = eopHang;
  607. #ifdef _WIN64
  608. if (argv[i][2] == L'6')
  609. f64bit = TRUE;
  610. #endif
  611. dwtid = _wtol(argv[++i]);
  612. if (argc > i + 1)
  613. {
  614. hevNotify = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE,
  615. FALSE, argv[++i]);
  616. }
  617. break;
  618. // dumps
  619. case L'D':
  620. case L'd':
  621. if (i + 3 >= argc || wszDump != NULL || eop != eopNone)
  622. goto done;
  623. eop = eopDump;
  624. ZeroMemory(&smdo, sizeof(smdo));
  625. smdo.ulMod = _wtol(argv[++i]);
  626. smdo.ulThread = _wtol(argv[++i]);
  627. wszDump = argv[++i];
  628. if (argv[i - 3][2] == L'T' || argv[i - 3][2] == L't')
  629. {
  630. if (i + 1 >= argc)
  631. goto done;
  632. smdo.dwThreadID = _wtol(argv[++i]);
  633. smdo.dfOptions = dfFilterThread;
  634. }
  635. else if (argv[i - 3][2] == L'S' || argv[i - 3][2] == L's')
  636. {
  637. if (i + 2 >= argc)
  638. goto done;
  639. smdo.dwThreadID = _wtol(argv[++i]);
  640. smdo.ulThreadEx = _wtol(argv[++i]);
  641. smdo.dfOptions = dfFilterThreadEx;
  642. }
  643. else if (argv[i - 3][2] == L'M' || argv[i - 3][2] == L'm')
  644. {
  645. HANDLE hmemRemote = NULL;
  646. LPVOID pvMem = NULL;
  647. LPWSTR wszShareSdmoName;
  648. if (i + 1 >= argc)
  649. goto done;
  650. hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwpid);
  651. if (hproc == NULL)
  652. {
  653. DWORD dwAwShit = GetLastError();
  654. goto done;
  655. }
  656. #ifdef _WIN64
  657. // hmemRemote = (HANDLE)_wtoi64(argv[++i]);
  658. #else
  659. // hmemRemote = (HANDLE)_wtol(argv[++i]);
  660. #endif
  661. wszShareSdmoName = argv[++i];
  662. if (wszShareSdmoName == NULL)
  663. {
  664. goto done;
  665. }
  666. hmem = OpenFileMappingW(FILE_MAP_WRITE,
  667. FALSE,
  668. wszShareSdmoName);
  669. if ((hmem == NULL) ||
  670. (hmem == INVALID_HANDLE_VALUE))
  671. {
  672. DWORD dwAwShit = GetLastError();
  673. goto done;
  674. }
  675. pvMem = MapViewOfFile(hmem, FILE_MAP_WRITE,
  676. 0, 0, 0);
  677. if (pvMem == NULL)
  678. goto done;
  679. psmdo = (SMDumpOptions *)pvMem;
  680. }
  681. break;
  682. default:
  683. goto done;
  684. }
  685. }
  686. ErrorTrace(0, " eop = %s", eopStr[eop]);
  687. // if we didn't get an operation, no point in doing anything else...
  688. if (eop == eopNone)
  689. goto done;
  690. if (GetSystemDirectoryW(wszMod, sizeofSTRW(wszMod)) == 0)
  691. {
  692. goto done;
  693. }
  694. StringCbCatW(wszMod, sizeof(wszMod), L"\\faultrep.dll");
  695. hmod = LoadLibraryExW(wszMod, NULL, 0);
  696. VALIDATEPARM(hr, (hmod == NULL));
  697. if (FAILED(hr))
  698. goto done;
  699. switch(eop)
  700. {
  701. // user or kernel faults:
  702. case eopEvent:
  703. ReportEvents(hmod, ct);
  704. break;
  705. // dumps
  706. case eopDump:
  707. {
  708. pfn_CREATEMINIDUMPW pfnCM;
  709. VALIDATEPARM(hr, (wszDump == NULL));
  710. if (FAILED(hr))
  711. goto done;
  712. pfnCM = (pfn_CREATEMINIDUMPW)GetProcAddress(hmod,
  713. "CreateMinidumpW");
  714. VALIDATEPARM(hr, (pfnCM == NULL));
  715. if (SUCCEEDED(hr))
  716. frrv = (*pfnCM)(dwpid, wszDump, psmdo) ? frrvOk : frrvErr;
  717. break;
  718. }
  719. // hangs
  720. case eopHang:
  721. {
  722. pfn_REPORTHANG pfnRH;
  723. pfnRH = (pfn_REPORTHANG)GetProcAddress(hmod, "ReportHang");
  724. VALIDATEPARM(hr, (pfnRH == NULL));
  725. if (SUCCEEDED(hr))
  726. frrv = (*pfnRH)(dwpid, dwtid, f64bit, hevNotify);
  727. break;
  728. }
  729. // err, shouldn't get here
  730. default:
  731. break;
  732. }
  733. done:
  734. if (hmod != NULL)
  735. FreeLibrary(hmod);
  736. if (hproc != NULL)
  737. CloseHandle(hproc);
  738. if (hmem != NULL)
  739. CloseHandle(hmem);
  740. if (hevNotify != NULL)
  741. CloseHandle(hevNotify);
  742. if (psmdo != NULL && psmdo != &smdo)
  743. UnmapViewOfFile((LPVOID)psmdo);
  744. return frrv;
  745. }