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.

1168 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. savedump.c
  5. Abstract:
  6. This module contains the code to recover a dump from the system paging
  7. file.
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include <savedump.h>
  13. //
  14. // Read/write copy of dump header.
  15. //
  16. BOOL Test = FALSE;
  17. /////////////////////////////////////////////////////////////////////////////
  18. // API for Dr. Watson / other fault handlers to call
  19. //
  20. // FaultTypeToReport: the type of fault, Kernel, snapshot, or ?
  21. // pwszDumpPath: a pointer to a string containing the dump or snapshot
  22. //
  23. // returns:
  24. // S_OK on success
  25. // some other system defined error code on failure
  26. // ***************************************************************************
  27. HRESULT
  28. PCHPFNotifyFault(EEventType FaultTypeToReport, LPWSTR pwszDumpPath, SEventInfoW *pEventInfo)
  29. {
  30. EFaultRepRetVal frrv;
  31. HMODULE hmodFaultRep;
  32. HRESULT hr = NOERROR;
  33. WCHAR wszDll[MAX_PATH];
  34. GetWindowsDirectoryW(wszDll, sizeof(wszDll) / sizeof(WCHAR));
  35. wcscat(wszDll, L"\\system32\\faultrep.dll");
  36. frrv = frrvErrNoDW;
  37. hmodFaultRep = LoadLibraryExW(wszDll, NULL, 0);
  38. if (hmodFaultRep != NULL)
  39. {
  40. pfn_REPORTEREVENT pfn;
  41. pfn = (pfn_REPORTEREVENT)GetProcAddress(hmodFaultRep,
  42. "ReportEREvent");
  43. if (pfn != NULL)
  44. {
  45. frrv = (*pfn)(FaultTypeToReport, pwszDumpPath, pEventInfo);
  46. }
  47. FreeLibrary(hmodFaultRep);
  48. hmodFaultRep = NULL;
  49. }
  50. hr = ((frrv != frrvErrNoDW) ? S_OK : HRESULT_FROM_WIN32(GetLastError()));
  51. return hr;
  52. }
  53. BOOLEAN
  54. CreateMiniDump(
  55. IN PWSTR FullDumpName,
  56. IN PWSTR MiniDumpName
  57. )
  58. {
  59. IDebugClient *DebugClient;
  60. PDEBUG_CONTROL DebugControl;
  61. HRESULT Hr;
  62. CHAR AnsiFullFileName[MAX_PATH];
  63. CHAR AnsiMiniFileName[MAX_PATH];
  64. if (WideCharToMultiByte(CP_ACP,
  65. 0,
  66. (PWSTR)FullDumpName,
  67. -1,
  68. AnsiFullFileName,
  69. sizeof(AnsiFullFileName),
  70. NULL,
  71. NULL) &&
  72. WideCharToMultiByte(CP_ACP,
  73. 0,
  74. (PWSTR)MiniDumpName,
  75. -1,
  76. AnsiMiniFileName,
  77. sizeof(AnsiMiniFileName),
  78. NULL,
  79. NULL))
  80. {
  81. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  82. (void **)&DebugClient)) != S_OK)
  83. {
  84. KdPrint (("SAVEDUMP: cannot create DebugClientInterface\n"));
  85. }
  86. else
  87. {
  88. if (DebugClient->QueryInterface(__uuidof(IDebugControl),
  89. (void **)&DebugControl) == S_OK)
  90. {
  91. if (DebugClient->OpenDumpFile(AnsiFullFileName) == S_OK)
  92. {
  93. DebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
  94. if (DebugClient->WriteDumpFile(AnsiMiniFileName,
  95. DEBUG_DUMP_SMALL) == S_OK)
  96. {
  97. Hr = S_OK;
  98. }
  99. }
  100. DebugControl->Release();
  101. }
  102. DebugClient->Release();
  103. }
  104. // Security descriptor issue.
  105. //
  106. //HANDLE MiniFileHandle;
  107. //
  108. //MiniFileHandle = CreateMyFile(miniFileName, FALSE, SecurityDescriptor);
  109. //if (MiniFileHandle != INVALID_HANDLE_VALUE)
  110. //{
  111. // CloseHandle( fileHandle );
  112. //}
  113. }
  114. return TRUE;
  115. }
  116. NTSTATUS
  117. GetTargetFileNames(
  118. IN HKEY CrashControlKey,
  119. IN PWSTR MiniFilePath,
  120. IN PWSTR FullFilePath,
  121. IN ULONG DumpType
  122. )
  123. {
  124. INT i;
  125. ULONG Status;
  126. ULONG Type;
  127. WCHAR FileName [ MAX_PATH + 1];
  128. ULONG Length;
  129. BOOL AddWack;
  130. SYSTEMTIME Time;
  131. WCHAR DirName [ MAX_PATH ];
  132. WCHAR ExpandedDirName [ MAX_PATH ];
  133. //
  134. // Minidump reads the directory from CrashControl\MiniDumpDir.
  135. //
  136. Length = sizeof (DirName);
  137. Status = RegQueryValueEx( CrashControlKey,
  138. L"MiniDumpDir",
  139. (LPDWORD) NULL,
  140. &Type,
  141. (LPBYTE) &DirName,
  142. &Length
  143. );
  144. if (Status != ERROR_SUCCESS) {
  145. //
  146. // Set to default.
  147. //
  148. wcscpy (DirName, L"%SystemRoot%\\Minidump");
  149. }
  150. ExpandEnvironmentStrings ( DirName, ExpandedDirName, MAX_PATH);
  151. //
  152. // If directory does not exist, create it. Ignore errors here because
  153. // they will be picked up later when we try to create the file.
  154. //
  155. CreateDirectory (ExpandedDirName, NULL);
  156. //
  157. // Format is: Mini-MM_DD_YY_HH_MM.dmp
  158. //
  159. GetLocalTime (&Time);
  160. if ( ExpandedDirName [ wcslen ( ExpandedDirName ) - 1 ] != L'\\' ) {
  161. AddWack = TRUE;
  162. } else {
  163. AddWack = FALSE;
  164. }
  165. for (i = 1; i < 100; i++) {
  166. swprintf (MiniFilePath,
  167. L"%s%sMini%2.2d%2.2d%2.2d-%2.2d.dmp",
  168. ExpandedDirName,
  169. AddWack ? L"\\" : L"",
  170. (int) Time.wMonth,
  171. (int) Time.wDay,
  172. (int) Time.wYear % 100,
  173. (int) i
  174. );
  175. if (GetFileAttributes (MiniFilePath) == (DWORD) -1 &&
  176. GetLastError () == ERROR_FILE_NOT_FOUND) {
  177. break;
  178. }
  179. }
  180. //
  181. // We failed to create a suitable file name; just fail.
  182. //
  183. if ( i == 100 ) {
  184. return STATUS_UNSUCCESSFUL;
  185. }
  186. if (DumpType != DUMP_TYPE_TRIAGE) {
  187. Length = sizeof (FileName);
  188. Status = RegQueryValueEx( CrashControlKey,
  189. L"DumpFile",
  190. (LPDWORD) NULL,
  191. &Type,
  192. (LPBYTE) &FileName,
  193. &Length
  194. );
  195. if (Status != ERROR_SUCCESS) {
  196. //
  197. // Set to default.
  198. //
  199. wcscpy (FileName, L"%SystemRoot%\\MEMORY.DMP");
  200. }
  201. ExpandEnvironmentStrings (FileName, FullFilePath, MAX_PATH );
  202. }
  203. return STATUS_SUCCESS;
  204. }
  205. VOID
  206. LogCrashDumpEvent(
  207. IN PUNICODE_STRING BugcheckString,
  208. IN PCWSTR SavedFileName,
  209. IN BOOL SuccessfullySavedDump
  210. )
  211. {
  212. HANDLE LogHandle;
  213. LPWSTR StringArray[3];
  214. WORD StringCount;
  215. DWORD EventId;
  216. BOOL Retry;
  217. DWORD Retries;
  218. //
  219. // Attempt to register the event source. Retry 20 times.
  220. //
  221. Retries = 0;
  222. do {
  223. LogHandle = RegisterEventSource( (LPWSTR) NULL,
  224. L"Save Dump"
  225. );
  226. //
  227. // Retry on specific failures (server unavailable and interface
  228. // unavailable).
  229. //
  230. if (LogHandle == NULL &&
  231. Retries < 20 &&
  232. ( GetLastError () == RPC_S_SERVER_UNAVAILABLE ||
  233. GetLastError () == RPC_S_UNKNOWN_IF) ) {
  234. Sleep ( 1500 );
  235. Retry = TRUE;
  236. } else {
  237. Retry = FALSE;
  238. }
  239. Retries++;
  240. } while (LogHandle == NULL && Retry);
  241. if (!LogHandle) {
  242. return ;
  243. }
  244. //
  245. // Set up the parameters based on whether a full crash or summary
  246. // was taken.
  247. //
  248. StringArray [ 0 ] = BugcheckString->Buffer;
  249. StringArray [ 1 ] = (PWSTR) SavedFileName;
  250. //
  251. // Report the appropriate event.
  252. //
  253. if (SuccessfullySavedDump) {
  254. EventId = EVENT_BUGCHECK_SAVED;
  255. StringCount = 2;
  256. } else {
  257. EventId = EVENT_BUGCHECK;
  258. StringCount = 2;
  259. }
  260. ReportEvent( LogHandle,
  261. EVENTLOG_INFORMATION_TYPE,
  262. 0,
  263. EventId,
  264. NULL,
  265. StringCount,
  266. 0,
  267. (LPCWSTR *)StringArray,
  268. NULL);
  269. }
  270. VOID
  271. SendCrashDumpAlert(
  272. IN PUNICODE_STRING BugcheckString,
  273. IN PCWSTR SavedFileName,
  274. IN BOOL SuccessfullySavedDump
  275. )
  276. {
  277. PADMIN_OTHER_INFO adminInfo;
  278. DWORD adminInfoSize;
  279. DWORD Length;
  280. DWORD i;
  281. ULONG winStatus;
  282. UCHAR VariableInfo [4096];
  283. //
  284. // Set up the administrator information variables for processing the
  285. // buffer.
  286. //
  287. adminInfo = (PADMIN_OTHER_INFO) VariableInfo;
  288. adminInfoSize = sizeof( ADMIN_OTHER_INFO );
  289. //
  290. // Format the bugcheck information into the appropriate message format.
  291. //
  292. RtlCopyMemory( (LPWSTR) ((PCHAR) adminInfo + adminInfoSize),
  293. BugcheckString->Buffer,
  294. BugcheckString->Length
  295. );
  296. adminInfoSize += BugcheckString->Length + sizeof( WCHAR );
  297. //
  298. // Set up the administrator alert information according to the type of
  299. // dump that was taken.
  300. //
  301. if (SuccessfullySavedDump) {
  302. adminInfo->alrtad_errcode = ALERT_BugCheckSaved;
  303. adminInfo->alrtad_numstrings = 3;
  304. wcscpy( (LPWSTR) ((PCHAR) adminInfo + adminInfoSize), SavedFileName);
  305. adminInfoSize += ((wcslen( SavedFileName ) + 1) * sizeof( WCHAR ));
  306. } else {
  307. adminInfo->alrtad_errcode = ALERT_BugCheck;
  308. adminInfo->alrtad_numstrings = 2;
  309. }
  310. //
  311. // Get the name of the computer and insert it into the buffer.
  312. //
  313. Length = (sizeof( VariableInfo ) - adminInfoSize) / sizeof(WCHAR);
  314. winStatus = GetComputerName( (LPWSTR) ((PCHAR) adminInfo + adminInfoSize),
  315. &Length );
  316. Length = ((Length + 1) * sizeof( WCHAR ));
  317. adminInfoSize += Length;
  318. //
  319. // Raise the alert.
  320. //
  321. i = 0;
  322. do {
  323. winStatus = NetAlertRaiseEx( ALERT_ADMIN_EVENT,
  324. adminInfo,
  325. adminInfoSize,
  326. L"SAVEDUMP" );
  327. if (winStatus) {
  328. if (winStatus == ERROR_FILE_NOT_FOUND) {
  329. if (i++ > 20) {
  330. break;
  331. }
  332. if ((i & 3) == 0) {
  333. KdPrint (( "SAVEDUMP: Waiting for alerter...\n" ));
  334. }
  335. Sleep( 15000 );
  336. }
  337. }
  338. } while (winStatus == ERROR_FILE_NOT_FOUND);
  339. }
  340. VOID
  341. GetSaveDumpInfo(
  342. IN ULONG BugCheckCode,
  343. IN ULONG_PTR BugCheckParameter1,
  344. IN ULONG_PTR BugCheckParameter2,
  345. IN ULONG_PTR BugCheckParameter3,
  346. IN ULONG_PTR BugCheckParameter4,
  347. IN ULONG MajorVersion,
  348. IN ULONG MinorVersion,
  349. OUT PUNICODE_STRING BugcheckString
  350. )
  351. {
  352. ANSI_STRING ansiString1;
  353. ANSI_STRING ansiString2;
  354. CHAR buffer1[256];
  355. CHAR buffer2[256];
  356. sprintf( buffer1,
  357. "0x%08x (0x%08x, 0x%08x, 0x%08x, 0x%08x)",
  358. BugCheckCode,
  359. BugCheckParameter1,
  360. BugCheckParameter2,
  361. BugCheckParameter3,
  362. BugCheckParameter4
  363. );
  364. RtlInitAnsiString( &ansiString1, buffer1 );
  365. RtlAnsiStringToUnicodeString( BugcheckString, &ansiString1, TRUE );
  366. sprintf( buffer2,
  367. "Microsoft Windows [v%ld.%ld]",
  368. MajorVersion,
  369. MinorVersion
  370. );
  371. }
  372. BOOL
  373. ReadDumpHeader(
  374. IN PWSTR DumpFileName,
  375. IN PDUMP_HEADER Header
  376. )
  377. {
  378. HANDLE File;
  379. ULONG Bytes;
  380. BOOL Succ;
  381. File = CreateFile (DumpFileName,
  382. GENERIC_READ,
  383. FILE_SHARE_READ,
  384. NULL,
  385. OPEN_EXISTING,
  386. 0,
  387. NULL
  388. );
  389. if (File == INVALID_HANDLE_VALUE) {
  390. return FALSE;
  391. }
  392. Succ = ReadFile (File,
  393. Header,
  394. sizeof (DUMP_HEADER),
  395. &Bytes,
  396. NULL);
  397. CloseHandle (File);
  398. if (Succ &&
  399. Header->Signature == DUMP_SIGNATURE &&
  400. Header->ValidDump == DUMP_VALID_DUMP) {
  401. return TRUE;
  402. }
  403. else
  404. {
  405. return FALSE;
  406. }
  407. }
  408. HRESULT
  409. DoDumpConv(
  410. PCHAR szInputDumpFile, // full or kernel dump
  411. PCHAR szOutputDumpFile, // triage dump file
  412. PCHAR szSymbolPath
  413. )
  414. {
  415. HRESULT Hr = E_FAIL;
  416. IDebugClient *DebugClient;
  417. IDebugControl *DebugControl;
  418. IDebugSymbols *DebugSymbols;
  419. if ((Hr = DebugCreate(__uuidof(IDebugClient),
  420. (void **)&DebugClient)) != S_OK)
  421. {
  422. return Hr;
  423. }
  424. if ((DebugClient->QueryInterface(__uuidof(IDebugControl),
  425. (void **)&DebugControl) == S_OK) &&
  426. (DebugClient->QueryInterface(__uuidof(IDebugSymbols),
  427. (void **)&DebugSymbols) == S_OK))
  428. {
  429. if (DebugClient->OpenDumpFile(szInputDumpFile) == S_OK)
  430. {
  431. // Optional. Conversion does not require symbols
  432. //if (DebugSymbols->SetSymbolPath("C:\\") == S_OK)
  433. if (szSymbolPath) {
  434. DebugSymbols->SetSymbolPath(szSymbolPath);
  435. }
  436. DebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
  437. if ((Hr = DebugClient->WriteDumpFile(szOutputDumpFile,
  438. DEBUG_DUMP_SMALL)) == S_OK)
  439. {
  440. Hr = S_OK;
  441. }
  442. }
  443. DebugControl->Release();
  444. DebugSymbols->Release();
  445. }
  446. DebugClient->Release();
  447. return Hr;
  448. }
  449. VOID
  450. SetSecurity(LPWSTR FileName)
  451. {
  452. PSID pLocalSystemSid;
  453. PSID pAdminSid;
  454. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY ;
  455. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY ;
  456. PSECURITY_DESCRIPTOR SecurityDescriptor;
  457. BYTE SDBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  458. PACL pAcl;
  459. BYTE AclBuffer[1024];
  460. HANDLE fileHandle;
  461. HANDLE Token;
  462. PTOKEN_OWNER pto;
  463. ULONG bl = 5;
  464. ULONG retlen;
  465. fileHandle = CreateFile(FileName,
  466. WRITE_DAC,
  467. 0,
  468. NULL,
  469. OPEN_EXISTING,
  470. FILE_ATTRIBUTE_NORMAL,
  471. 0);
  472. if (fileHandle == INVALID_HANDLE_VALUE)
  473. {
  474. return;
  475. }
  476. RtlAllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID,
  477. 0, 0, 0, 0, 0, 0, 0, &pLocalSystemSid );
  478. RtlAllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  479. DOMAIN_ALIAS_RID_ADMINS,
  480. 0, 0, 0, 0, 0, 0, &pAdminSid );
  481. SecurityDescriptor = (PSECURITY_DESCRIPTOR) SDBuffer;
  482. //
  483. // You can be fancy and compute the exact size, but since the
  484. // security descriptor capture code has to do that anyway, why
  485. // do it twice?
  486. //
  487. pAcl = (PACL) AclBuffer;
  488. RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
  489. RtlCreateAcl(pAcl, 1024, ACL_REVISION);
  490. //
  491. // current user, Administrator and system have full control
  492. //
  493. if (OpenThreadToken(GetCurrentThread (), MAXIMUM_ALLOWED, TRUE, &Token) ||
  494. OpenProcessToken(GetCurrentProcess (), MAXIMUM_ALLOWED, &Token))
  495. {
  496. realloc:
  497. pto = (PTOKEN_OWNER)malloc(bl);
  498. if (pto)
  499. {
  500. if (GetTokenInformation(Token, TokenOwner, pto, bl, &retlen))
  501. {
  502. RtlAddAccessAllowedAce(pAcl,
  503. ACL_REVISION,
  504. GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
  505. pto->Owner);
  506. }
  507. else if (bl < retlen)
  508. {
  509. bl = retlen;
  510. free (pto);
  511. goto realloc;
  512. }
  513. free (pto);
  514. }
  515. CloseHandle(Token);
  516. }
  517. if (pAdminSid)
  518. {
  519. RtlAddAccessAllowedAce(pAcl,
  520. ACL_REVISION,
  521. GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
  522. pAdminSid);
  523. RtlFreeSid(pAdminSid);
  524. }
  525. if (pLocalSystemSid)
  526. {
  527. RtlAddAccessAllowedAce(pAcl,
  528. ACL_REVISION,
  529. GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
  530. pLocalSystemSid);
  531. RtlFreeSid(pLocalSystemSid);
  532. }
  533. RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, pAcl, FALSE);
  534. RtlSetOwnerSecurityDescriptor(SecurityDescriptor, pAdminSid, FALSE);
  535. NtSetSecurityObject(fileHandle,
  536. DACL_SECURITY_INFORMATION,
  537. SecurityDescriptor);
  538. CloseHandle(fileHandle);
  539. }
  540. BOOL
  541. BugcheckEventHandler(
  542. IN BOOL NotifyPcHealth,
  543. OUT PBOOL SavedDump,
  544. OUT PULONG LogEvent,
  545. OUT PULONG SendAlert,
  546. OUT PUNICODE_STRING BugCheckString,
  547. OUT PWCHAR FileName
  548. )
  549. /*++
  550. Routine Description:
  551. This is the boot time routine to handle pending bugcheck event.
  552. Arguments:
  553. NotifyPcHealth - TRUE if we should report event to PC Health, FALSE otherwise.
  554. Return Value:
  555. TRUE if bugcheck event found and reported to PC Health, FALSE otherwise.
  556. --*/
  557. {
  558. NTSTATUS Status;
  559. DUMP_HEADER Header;
  560. ULONG WinStatus;
  561. HKEY Key;
  562. ULONG Length;
  563. ULONG Overwrite;
  564. ULONG Type;
  565. ULONG TempDestination = 0;
  566. WCHAR MiniDumpName[MAX_PATH];
  567. WCHAR FullDumpName[MAX_PATH];
  568. PWCHAR FinalFileName;
  569. WCHAR SourceDumpName[MAX_PATH];
  570. BOOL Succ;
  571. *SavedDump = FALSE;
  572. *LogEvent = 0;
  573. *SendAlert = 0;
  574. Succ = FALSE;
  575. Overwrite = FALSE;
  576. FinalFileName = NULL;
  577. WinStatus = RegOpenKey( HKEY_LOCAL_MACHINE,
  578. SUBKEY_CRASH_CONTROL L"\\MachineCrash",
  579. &Key );
  580. if (WinStatus != ERROR_SUCCESS) {
  581. return FALSE;
  582. }
  583. Length = sizeof (Length);
  584. WinStatus = RegQueryValueEx( Key,
  585. L"TempDestination",
  586. (LPDWORD) NULL,
  587. &Type,
  588. (LPBYTE) &TempDestination,
  589. &Length );
  590. Length = sizeof (SourceDumpName);
  591. WinStatus = RegQueryValueEx( Key,
  592. L"DumpFile",
  593. (LPDWORD) NULL,
  594. &Type,
  595. (LPBYTE) &SourceDumpName,
  596. &Length );
  597. RegCloseKey (Key);
  598. if ((WinStatus != NO_ERROR) ||
  599. !ReadDumpHeader (SourceDumpName, &Header))
  600. {
  601. //
  602. // Dump file is not present or invalid.
  603. //
  604. return FALSE;
  605. }
  606. //
  607. // Open the base registry node for crash control information and get the
  608. // actions for what needs to occur next.
  609. //
  610. WinStatus = RegOpenKey (HKEY_LOCAL_MACHINE,
  611. SUBKEY_CRASH_CONTROL,
  612. &Key);
  613. if (WinStatus != ERROR_SUCCESS) {
  614. return FALSE;
  615. }
  616. Length = 4;
  617. WinStatus = RegQueryValueEx (Key,
  618. L"LogEvent",
  619. (LPDWORD) NULL,
  620. &Type,
  621. (LPBYTE) LogEvent,
  622. &Length);
  623. WinStatus = RegQueryValueEx (Key,
  624. L"SendAlert",
  625. (LPDWORD) NULL,
  626. &Type,
  627. (LPBYTE) SendAlert,
  628. &Length);
  629. //
  630. // If the dump file needs to be copied, copy it now.
  631. //
  632. Status = GetTargetFileNames (Key,
  633. MiniDumpName,
  634. FullDumpName,
  635. Header.DumpType);
  636. if (!NT_SUCCESS (Status)) {
  637. goto fileDone;
  638. }
  639. if (!TempDestination) {
  640. FinalFileName = SourceDumpName;
  641. *SavedDump = TRUE;
  642. } else {
  643. Overwrite = 0;
  644. WinStatus = RegQueryValueEx (Key,
  645. L"Overwrite",
  646. (LPDWORD) NULL,
  647. &Type,
  648. (LPBYTE) &Overwrite,
  649. &Length);
  650. if (!Test) {
  651. //
  652. // Set the priority class of this application down to the Lowest
  653. // priority class to ensure that copying the file does not overload
  654. // everything else that is going on during system initialization.
  655. //
  656. //
  657. // We do not lower the priority in test mode because it just
  658. // wastes time.
  659. //
  660. SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS);
  661. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
  662. }
  663. if (Header.DumpType == DUMP_TYPE_FULL ||
  664. Header.DumpType == DUMP_TYPE_SUMMARY) {
  665. FinalFileName = FullDumpName;
  666. *SavedDump = CopyFileEx (SourceDumpName,
  667. FullDumpName,
  668. NULL,
  669. NULL,
  670. NULL,
  671. Overwrite ? 0 : COPY_FILE_FAIL_IF_EXISTS);
  672. } else if (Header.DumpType == DUMP_TYPE_TRIAGE) {
  673. FinalFileName = MiniDumpName;
  674. *SavedDump = CopyFileEx (SourceDumpName,
  675. MiniDumpName,
  676. NULL,
  677. NULL,
  678. NULL,
  679. 0);
  680. }
  681. //
  682. // NOTE: MoveFileEx would do the Copy and Delete as one action,
  683. // which may be desirable.
  684. //
  685. if (*SavedDump)
  686. {
  687. DeleteFile (SourceDumpName);
  688. }
  689. }
  690. fileDone:
  691. RegCloseKey (Key);
  692. if (*SavedDump) {
  693. #if DBG
  694. ASSERT (FinalFileName != NULL);
  695. #endif
  696. //
  697. // Set the security on the file
  698. //
  699. SetSecurity(FinalFileName);
  700. }
  701. if (FinalFileName != NULL) {
  702. wcscpy(FileName, FinalFileName);
  703. }
  704. GetSaveDumpInfo (Header.BugCheckCode,
  705. Header.BugCheckParameter1,
  706. Header.BugCheckParameter2,
  707. Header.BugCheckParameter3,
  708. Header.BugCheckParameter4,
  709. Header.MajorVersion,
  710. Header.MinorVersion,
  711. BugCheckString);
  712. //
  713. // Copy a minidump out, if necessary.
  714. //
  715. if (*SavedDump &&
  716. (Header.DumpType == DUMP_TYPE_FULL ||
  717. Header.DumpType == DUMP_TYPE_SUMMARY)) {
  718. CreateMiniDump (FullDumpName, MiniDumpName);
  719. }
  720. //
  721. // Whenever we have had a blue creen event we are going to post an unexpected restart
  722. // shutdown event screen on startup (assuming Server SKU or specially set Professional).
  723. // In order to make it easier on the user we attempt to prefill the comment with the bug
  724. // check data. If and only if we got to this point before he has first logged in.
  725. //
  726. //
  727. // Open the Reliability key.
  728. //
  729. Status = RegOpenKey(HKEY_LOCAL_MACHINE,
  730. SUBKEY_RELIABILITY,
  731. &Key);
  732. if (Status == ERROR_SUCCESS) {
  733. //
  734. // Is Dirty Shutdown set?
  735. //
  736. Length = MAX_PATH;
  737. Status = RegQueryValueEx(Key,
  738. L"DirtyShutDown",
  739. NULL,
  740. &Type,
  741. (LPBYTE)SourceDumpName,
  742. &Length);
  743. //
  744. // Preload the set comment.
  745. //
  746. if (Status == ERROR_SUCCESS) {
  747. Status = RegSetValueEx(Key,
  748. L"BugCheckString",
  749. NULL,
  750. REG_SZ,
  751. (LPBYTE)(BugCheckString->Buffer),
  752. BugCheckString->Length);
  753. }
  754. RegCloseKey(Key);
  755. }
  756. //
  757. // Report it to PC Health.
  758. //
  759. if (NotifyPcHealth)
  760. {
  761. PCHPFNotifyFault(eetKernelFault, MiniDumpName, NULL);
  762. return TRUE;
  763. }
  764. return FALSE;
  765. }
  766. void Usage()
  767. {
  768. fprintf(stderr,"savedump -c input_dump_file output_dump_file\n");
  769. fprintf(stderr,"\tinput dump file is full or kernel crash dump.\n");
  770. fprintf(stderr,"\toutput is triage crash dump.\n");
  771. }
  772. VOID
  773. __cdecl
  774. main(
  775. int argc,
  776. char *argv[]
  777. )
  778. /*++
  779. Routine Description:
  780. This is the main driving routine for the dump recovery process.
  781. Arguments:
  782. None.
  783. Return Value:
  784. None.
  785. --*/
  786. {
  787. BOOL DumpConv;
  788. PCHAR ConvDumpFrom;
  789. PCHAR ConvDumpTo;
  790. PCHAR SymbolPath;
  791. LONG arg;
  792. ULONG WinStatus;
  793. HKEY Key;
  794. BOOL SavedDump;
  795. ULONG LogEvent;
  796. ULONG SendAlert;
  797. UNICODE_STRING BugCheckString;
  798. WCHAR FileName[MAX_PATH];
  799. PWCHAR FinalFileName;
  800. DumpConv = FALSE;
  801. ConvDumpTo = NULL;
  802. ConvDumpFrom = NULL;
  803. SymbolPath = NULL;
  804. SavedDump = FALSE;
  805. LogEvent = 0;
  806. SendAlert = 0;
  807. *FileName = UNICODE_NULL;
  808. FinalFileName = NULL;
  809. for (arg = 1; arg < argc; arg++) {
  810. if (argv[arg][0] == '-' || argv[arg][0] == '/') {
  811. switch (argv[arg][1]) {
  812. case 'c':
  813. case 'C':
  814. DumpConv = TRUE;
  815. if (arg+2<argc) {
  816. ConvDumpFrom = argv[++arg];
  817. ConvDumpTo = argv[++arg];
  818. } else {
  819. Usage();
  820. exit (-1);
  821. }
  822. break;
  823. #if DBG
  824. case 'y':
  825. case 'Y':
  826. if (++arg < argc) {
  827. SymbolPath = argv[arg];
  828. }
  829. break;
  830. case 't':
  831. case 'T':
  832. Test = TRUE;
  833. break;
  834. #endif
  835. default:
  836. break;
  837. }
  838. }
  839. }
  840. if (DumpConv) {
  841. if (!ConvDumpFrom || !ConvDumpTo) {
  842. Usage();
  843. exit (-1);
  844. }
  845. if (DoDumpConv(ConvDumpFrom, ConvDumpTo, SymbolPath) != S_OK) {
  846. fprintf(stderr, "Dump conversion failed, please check in source dump is vaild\n"
  847. "by loading it in the debugger as 'kd.exe -z <dump> -y <symbols>\n");
  848. }
  849. ANSI_STRING ansiString;
  850. UNICODE_STRING unicodeString;
  851. WCHAR buffer[MAX_PATH+1];
  852. unicodeString.Buffer = buffer;
  853. unicodeString.MaximumLength = MAX_PATH*sizeof(WCHAR);
  854. unicodeString.Length = 0;
  855. RtlInitAnsiString( &ansiString, ConvDumpTo );
  856. RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, FALSE );
  857. buffer[unicodeString.Length / sizeof(WCHAR)] = 0;
  858. SetSecurity(buffer);
  859. return;
  860. }
  861. //
  862. // Handle dirty shutdown events.
  863. //
  864. BugcheckEventHandler(TRUE,
  865. &SavedDump,
  866. &LogEvent,
  867. &SendAlert,
  868. &BugCheckString,
  869. FileName);
  870. WatchdogEventHandler(TRUE);
  871. DirtyShutdownEventHandler(TRUE);
  872. //
  873. // Knock down reliability ShutdownEventPending flag. We must always try to do this
  874. // since somebody can set this flag and recover later on (e.g. watchdog's EventFlag
  875. // cleared). With this flag set savedump will always run and we don't want that.
  876. //
  877. // Note: This flag is shared between multiple components. Only savedump is allowed
  878. // to clear this flag, all others components are only allowed to set it to trigger
  879. // savedump run at next logon.
  880. //
  881. WinStatus = RegOpenKey(HKEY_LOCAL_MACHINE,
  882. SUBKEY_RELIABILITY,
  883. &Key);
  884. if (ERROR_SUCCESS == WinStatus)
  885. {
  886. RegDeleteValue(Key, L"ShutdownEventPending");
  887. RegCloseKey(Key);
  888. }
  889. //
  890. // We delay time consuming opertaions till the end. We had the case where SendCrashDumpAlert
  891. // delayed PC Health pop-ups few minutes.
  892. //
  893. if (SavedDump) {
  894. FinalFileName = FileName;
  895. }
  896. if (LogEvent) {
  897. LogCrashDumpEvent (&BugCheckString,
  898. FinalFileName,
  899. SavedDump);
  900. }
  901. if (SendAlert) {
  902. SendCrashDumpAlert (&BugCheckString,
  903. FinalFileName,
  904. SavedDump);
  905. }
  906. //
  907. // BUGBUG: We should call RtlFreeUnicodeString for BugCheckString (and somehow determine
  908. // if it was allocated). I'm not doing this now since original code didn't do this
  909. // either and I don't want to introduce additional complexity at this moment.
  910. //
  911. }