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.

389 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. bugcheck.c
  5. Abstract:
  6. Port library routines for handling bugcheck callbacks.
  7. Author:
  8. Matthew D Hendel (math) 4-April-2002
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Definitions
  14. //
  15. #define PORT_BUGCHECK_TAG ('dBlP')
  16. //
  17. // Internal structures.
  18. //
  19. typedef struct _PORT_BUGCHECK_DATA {
  20. PVOID Buffer;
  21. ULONG BufferLength;
  22. ULONG BufferUsed;
  23. GUID Guid;
  24. PPORT_BUGCHECK_CALLBACK_ROUTINE CallbackRoutine;
  25. KBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  26. KBUGCHECK_REASON_CALLBACK_RECORD SecondaryCallbackRecord;
  27. } PORT_BUGCHECK_DATA, *PPORT_BUGCHECK_DATA;
  28. //
  29. // Global Variables
  30. //
  31. PPORT_BUGCHECK_DATA PortBugcheckData;
  32. //
  33. // Imports
  34. //
  35. extern PULONG_PTR KiBugCheckData;
  36. //
  37. // Prototypes
  38. //
  39. VOID
  40. PortBugcheckGatherDataCallback(
  41. IN KBUGCHECK_CALLBACK_REASON Reason,
  42. IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
  43. IN OUT PVOID ReasonSpecificData,
  44. IN ULONG ReasonSpecificDataLength
  45. );
  46. VOID
  47. PortBugcheckWriteDataCallback(
  48. IN KBUGCHECK_CALLBACK_REASON Reason,
  49. IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
  50. IN OUT PVOID ReasonSpecificData,
  51. IN ULONG ReasonSpecificDataLength
  52. );
  53. //
  54. // Implementation
  55. //
  56. NTSTATUS
  57. PortRegisterBugcheckCallback(
  58. IN PCGUID BugcheckDataGuid,
  59. IN PPORT_BUGCHECK_CALLBACK_ROUTINE BugcheckRoutine
  60. )
  61. /*++
  62. Routine Description:
  63. Register a bugcheck callback routine.
  64. Arguments:
  65. BugcheckDataGuid - A GUID used to identify the data in the dump.
  66. BugcheckRoutine - Routine called when a bugcheck occurs.
  67. Return Value:
  68. NTSTATUS code.
  69. --*/
  70. {
  71. BOOLEAN Succ;
  72. NTSTATUS Status;
  73. PVOID Temp;
  74. PPORT_BUGCHECK_DATA BugcheckData;
  75. PVOID Buffer;
  76. ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL);
  77. Status = STATUS_SUCCESS;
  78. BugcheckData = ExAllocatePoolWithTag (NonPagedPool,
  79. sizeof (PORT_BUGCHECK_DATA),
  80. PORT_BUGCHECK_TAG);
  81. if (BugcheckData == NULL) {
  82. Status = STATUS_NO_MEMORY;
  83. goto done;
  84. }
  85. RtlZeroMemory (BugcheckData, sizeof (PORT_BUGCHECK_DATA));
  86. Buffer = ExAllocatePoolWithTag (NonPagedPool,
  87. PAGE_SIZE,
  88. PORT_BUGCHECK_TAG);
  89. if (Buffer == NULL) {
  90. Status = STATUS_NO_MEMORY;
  91. goto done;
  92. }
  93. BugcheckData->Buffer = Buffer;
  94. BugcheckData->BufferLength = 2 * PAGE_SIZE;
  95. BugcheckData->CallbackRoutine = BugcheckRoutine;
  96. BugcheckData->Guid = *BugcheckDataGuid;
  97. //
  98. // If PortBugcheckData == NULL, swap the values, otherwise fail the
  99. // function.
  100. //
  101. Temp = InterlockedCompareExchangePointer (&PortBugcheckData,
  102. BugcheckData,
  103. NULL);
  104. if (Temp != NULL) {
  105. Status = STATUS_UNSUCCESSFUL;
  106. goto done;
  107. }
  108. KeInitializeCallbackRecord (&BugcheckData->CallbackRecord);
  109. KeInitializeCallbackRecord (&BugcheckData->SecondaryCallbackRecord);
  110. //
  111. // This registers the bugcheck "gather data" function.
  112. //
  113. Succ = KeRegisterBugCheckReasonCallback (&BugcheckData->CallbackRecord,
  114. PortBugcheckGatherDataCallback,
  115. KbCallbackReserved1,
  116. "PL");
  117. if (!Succ) {
  118. Status = STATUS_UNSUCCESSFUL;
  119. goto done;
  120. }
  121. Succ = KeRegisterBugCheckReasonCallback (&BugcheckData->SecondaryCallbackRecord,
  122. PortBugcheckWriteDataCallback,
  123. KbCallbackSecondaryDumpData,
  124. "PL");
  125. if (!Succ) {
  126. Status = STATUS_UNSUCCESSFUL;
  127. goto done;
  128. }
  129. done:
  130. if (!NT_SUCCESS (Status)) {
  131. PortDeregisterBugcheckCallback (BugcheckDataGuid);
  132. }
  133. return STATUS_SUCCESS;
  134. }
  135. NTSTATUS
  136. PortDeregisterBugcheckCallback(
  137. IN PCGUID BugcheckDataGuid
  138. )
  139. /*++
  140. Routine Description:
  141. Deregister a bugcheck callback routine previously registered by
  142. PortRegisterBugcheckCallback.
  143. Arguments:
  144. BugcheckDataGuid - Guid associated with the data stream to deregister.
  145. Return Value:
  146. NTSTATUS code.
  147. --*/
  148. {
  149. PPORT_BUGCHECK_DATA BugcheckData;
  150. BugcheckData = InterlockedExchangePointer (&PortBugcheckData, NULL);
  151. if (BugcheckData == NULL ||
  152. !IsEqualGUID (&BugcheckData->Guid, BugcheckDataGuid)) {
  153. return STATUS_UNSUCCESSFUL;
  154. }
  155. KeDeregisterBugCheckReasonCallback (&BugcheckData->SecondaryCallbackRecord);
  156. KeDeregisterBugCheckReasonCallback (&BugcheckData->CallbackRecord);
  157. if (BugcheckData->Buffer != NULL) {
  158. ExFreePoolWithTag (BugcheckData->Buffer, PORT_BUGCHECK_TAG);
  159. BugcheckData->Buffer = NULL;
  160. }
  161. ExFreePoolWithTag (BugcheckData, PORT_BUGCHECK_TAG);
  162. return STATUS_SUCCESS;
  163. }
  164. VOID
  165. PortBugcheckGatherDataCallback(
  166. IN KBUGCHECK_CALLBACK_REASON Reason,
  167. IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
  168. IN OUT PVOID ReasonSpecificData,
  169. IN ULONG ReasonSpecificDataLength
  170. )
  171. /*++
  172. Routine Description:
  173. Port driver routine to gather data during a bugcheck.
  174. Arguments:
  175. Reason - Must be KbCallbackReserved1.
  176. Record - Supplies the bugcheck record previously registered.
  177. ReasonSpecificData - Not used.
  178. ReasonSpecificDataLength - Not used.
  179. Return Value:
  180. None.
  181. Environment:
  182. The routine is called from bugcheck context: at HIGH_LEVEL, with
  183. interrupts disabled and other processors stalled.
  184. --*/
  185. {
  186. NTSTATUS Status;
  187. KBUGCHECK_DATA BugcheckData;
  188. //
  189. // On multiproc we only go till IPI_LEVEL
  190. //
  191. ASSERT (KeGetCurrentIrql() >= IPI_LEVEL);
  192. ASSERT (Reason == KbCallbackReserved1);
  193. ASSERT (PortBugcheckData != NULL);
  194. ASSERT (PortBugcheckData->BufferUsed == 0);
  195. BugcheckData.BugCheckCode = (ULONG)KiBugCheckData[0];
  196. BugcheckData.BugCheckParameter1 = KiBugCheckData[1];
  197. BugcheckData.BugCheckParameter2 = KiBugCheckData[2];
  198. BugcheckData.BugCheckParameter3 = KiBugCheckData[3];
  199. BugcheckData.BugCheckParameter4 = KiBugCheckData[4];
  200. //
  201. // Gather data, put it in the buffer.
  202. //
  203. Status = PortBugcheckData->CallbackRoutine (&BugcheckData,
  204. PortBugcheckData->Buffer,
  205. PortBugcheckData->BufferLength,
  206. &PortBugcheckData->BufferUsed);
  207. if (!NT_SUCCESS (Status)) {
  208. PortBugcheckData->BufferUsed = 0;
  209. }
  210. }
  211. VOID
  212. PortBugcheckWriteDataCallback(
  213. IN KBUGCHECK_CALLBACK_REASON Reason,
  214. IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
  215. IN OUT PVOID ReasonSpecificData,
  216. IN ULONG ReasonSpecificDataLength
  217. )
  218. /*++
  219. Routine Description:
  220. Port driver routine to write data out during a bugcheck.
  221. Arguments:
  222. Reason - Must be KbCallbackSecondaryData.
  223. Record - Supplies the bugcheck record previously registered.
  224. ReasonSpecificData - Pointer to KBUGCHECK_SECONDARY_DUMP_DATA structure.
  225. ReasonSpecificDataLength - Sizeof ReasonSpecificData buffer.
  226. Return Value:
  227. None.
  228. Environment:
  229. The routine is called from bugcheck context: at HIGH_LEVEL, with
  230. interrupts disabled and other processors stalled.
  231. --*/
  232. {
  233. PKBUGCHECK_SECONDARY_DUMP_DATA SecondaryData;
  234. //
  235. // On multiproc we only go till IPI_LEVEL
  236. //
  237. ASSERT (KeGetCurrentIrql() >= IPI_LEVEL);
  238. ASSERT (ReasonSpecificDataLength >= sizeof(KBUGCHECK_SECONDARY_DUMP_DATA));
  239. ASSERT (Reason == KbCallbackSecondaryDumpData);
  240. SecondaryData = (PKBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData;
  241. //
  242. // This means we have no data to provide.
  243. //
  244. if (PortBugcheckData->BufferUsed == 0) {
  245. return ;
  246. }
  247. //
  248. // If OutBuffer is NULL, then this is a request for sizing information
  249. // only. Do not fill in the rest of the data.
  250. //
  251. if (SecondaryData->OutBuffer == NULL) {
  252. SecondaryData->Guid = PortBugcheckData->Guid;
  253. SecondaryData->OutBuffer = PortBugcheckData->Buffer;
  254. SecondaryData->OutBufferLength = PortBugcheckData->BufferUsed;
  255. return ;
  256. }
  257. //
  258. // Is there enough space?
  259. //
  260. if (SecondaryData->MaximumAllowed < PortBugcheckData->BufferUsed) {
  261. return ;
  262. }
  263. SecondaryData->Guid = PortBugcheckData->Guid;
  264. SecondaryData->OutBuffer = PortBugcheckData->Buffer;
  265. SecondaryData->OutBufferLength = PortBugcheckData->BufferUsed;
  266. }