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

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
bugcheck.c
Abstract:
Port library routines for handling bugcheck callbacks.
Author:
Matthew D Hendel (math) 4-April-2002
Revision History:
--*/
#include "precomp.h"
//
// Definitions
//
#define PORT_BUGCHECK_TAG ('dBlP')
//
// Internal structures.
//
typedef struct _PORT_BUGCHECK_DATA {
PVOID Buffer;
ULONG BufferLength;
ULONG BufferUsed;
GUID Guid;
PPORT_BUGCHECK_CALLBACK_ROUTINE CallbackRoutine;
KBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
KBUGCHECK_REASON_CALLBACK_RECORD SecondaryCallbackRecord;
} PORT_BUGCHECK_DATA, *PPORT_BUGCHECK_DATA;
//
// Global Variables
//
PPORT_BUGCHECK_DATA PortBugcheckData;
//
// Imports
//
extern PULONG_PTR KiBugCheckData;
//
// Prototypes
//
VOID
PortBugcheckGatherDataCallback(
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
);
VOID
PortBugcheckWriteDataCallback(
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
);
//
// Implementation
//
NTSTATUS
PortRegisterBugcheckCallback(
IN PCGUID BugcheckDataGuid,
IN PPORT_BUGCHECK_CALLBACK_ROUTINE BugcheckRoutine
)
/*++
Routine Description:
Register a bugcheck callback routine.
Arguments:
BugcheckDataGuid - A GUID used to identify the data in the dump.
BugcheckRoutine - Routine called when a bugcheck occurs.
Return Value:
NTSTATUS code.
--*/
{
BOOLEAN Succ;
NTSTATUS Status;
PVOID Temp;
PPORT_BUGCHECK_DATA BugcheckData;
PVOID Buffer;
ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL);
Status = STATUS_SUCCESS;
BugcheckData = ExAllocatePoolWithTag (NonPagedPool,
sizeof (PORT_BUGCHECK_DATA),
PORT_BUGCHECK_TAG);
if (BugcheckData == NULL) {
Status = STATUS_NO_MEMORY;
goto done;
}
RtlZeroMemory (BugcheckData, sizeof (PORT_BUGCHECK_DATA));
Buffer = ExAllocatePoolWithTag (NonPagedPool,
PAGE_SIZE,
PORT_BUGCHECK_TAG);
if (Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto done;
}
BugcheckData->Buffer = Buffer;
BugcheckData->BufferLength = 2 * PAGE_SIZE;
BugcheckData->CallbackRoutine = BugcheckRoutine;
BugcheckData->Guid = *BugcheckDataGuid;
//
// If PortBugcheckData == NULL, swap the values, otherwise fail the
// function.
//
Temp = InterlockedCompareExchangePointer (&PortBugcheckData,
BugcheckData,
NULL);
if (Temp != NULL) {
Status = STATUS_UNSUCCESSFUL;
goto done;
}
KeInitializeCallbackRecord (&BugcheckData->CallbackRecord);
KeInitializeCallbackRecord (&BugcheckData->SecondaryCallbackRecord);
//
// This registers the bugcheck "gather data" function.
//
Succ = KeRegisterBugCheckReasonCallback (&BugcheckData->CallbackRecord,
PortBugcheckGatherDataCallback,
KbCallbackReserved1,
"PL");
if (!Succ) {
Status = STATUS_UNSUCCESSFUL;
goto done;
}
Succ = KeRegisterBugCheckReasonCallback (&BugcheckData->SecondaryCallbackRecord,
PortBugcheckWriteDataCallback,
KbCallbackSecondaryDumpData,
"PL");
if (!Succ) {
Status = STATUS_UNSUCCESSFUL;
goto done;
}
done:
if (!NT_SUCCESS (Status)) {
PortDeregisterBugcheckCallback (BugcheckDataGuid);
}
return STATUS_SUCCESS;
}
NTSTATUS
PortDeregisterBugcheckCallback(
IN PCGUID BugcheckDataGuid
)
/*++
Routine Description:
Deregister a bugcheck callback routine previously registered by
PortRegisterBugcheckCallback.
Arguments:
BugcheckDataGuid - Guid associated with the data stream to deregister.
Return Value:
NTSTATUS code.
--*/
{
PPORT_BUGCHECK_DATA BugcheckData;
BugcheckData = InterlockedExchangePointer (&PortBugcheckData, NULL);
if (BugcheckData == NULL ||
!IsEqualGUID (&BugcheckData->Guid, BugcheckDataGuid)) {
return STATUS_UNSUCCESSFUL;
}
KeDeregisterBugCheckReasonCallback (&BugcheckData->SecondaryCallbackRecord);
KeDeregisterBugCheckReasonCallback (&BugcheckData->CallbackRecord);
if (BugcheckData->Buffer != NULL) {
ExFreePoolWithTag (BugcheckData->Buffer, PORT_BUGCHECK_TAG);
BugcheckData->Buffer = NULL;
}
ExFreePoolWithTag (BugcheckData, PORT_BUGCHECK_TAG);
return STATUS_SUCCESS;
}
VOID
PortBugcheckGatherDataCallback(
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
)
/*++
Routine Description:
Port driver routine to gather data during a bugcheck.
Arguments:
Reason - Must be KbCallbackReserved1.
Record - Supplies the bugcheck record previously registered.
ReasonSpecificData - Not used.
ReasonSpecificDataLength - Not used.
Return Value:
None.
Environment:
The routine is called from bugcheck context: at HIGH_LEVEL, with
interrupts disabled and other processors stalled.
--*/
{
NTSTATUS Status;
KBUGCHECK_DATA BugcheckData;
//
// On multiproc we only go till IPI_LEVEL
//
ASSERT (KeGetCurrentIrql() >= IPI_LEVEL);
ASSERT (Reason == KbCallbackReserved1);
ASSERT (PortBugcheckData != NULL);
ASSERT (PortBugcheckData->BufferUsed == 0);
BugcheckData.BugCheckCode = (ULONG)KiBugCheckData[0];
BugcheckData.BugCheckParameter1 = KiBugCheckData[1];
BugcheckData.BugCheckParameter2 = KiBugCheckData[2];
BugcheckData.BugCheckParameter3 = KiBugCheckData[3];
BugcheckData.BugCheckParameter4 = KiBugCheckData[4];
//
// Gather data, put it in the buffer.
//
Status = PortBugcheckData->CallbackRoutine (&BugcheckData,
PortBugcheckData->Buffer,
PortBugcheckData->BufferLength,
&PortBugcheckData->BufferUsed);
if (!NT_SUCCESS (Status)) {
PortBugcheckData->BufferUsed = 0;
}
}
VOID
PortBugcheckWriteDataCallback(
IN KBUGCHECK_CALLBACK_REASON Reason,
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
IN OUT PVOID ReasonSpecificData,
IN ULONG ReasonSpecificDataLength
)
/*++
Routine Description:
Port driver routine to write data out during a bugcheck.
Arguments:
Reason - Must be KbCallbackSecondaryData.
Record - Supplies the bugcheck record previously registered.
ReasonSpecificData - Pointer to KBUGCHECK_SECONDARY_DUMP_DATA structure.
ReasonSpecificDataLength - Sizeof ReasonSpecificData buffer.
Return Value:
None.
Environment:
The routine is called from bugcheck context: at HIGH_LEVEL, with
interrupts disabled and other processors stalled.
--*/
{
PKBUGCHECK_SECONDARY_DUMP_DATA SecondaryData;
//
// On multiproc we only go till IPI_LEVEL
//
ASSERT (KeGetCurrentIrql() >= IPI_LEVEL);
ASSERT (ReasonSpecificDataLength >= sizeof(KBUGCHECK_SECONDARY_DUMP_DATA));
ASSERT (Reason == KbCallbackSecondaryDumpData);
SecondaryData = (PKBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData;
//
// This means we have no data to provide.
//
if (PortBugcheckData->BufferUsed == 0) {
return ;
}
//
// If OutBuffer is NULL, then this is a request for sizing information
// only. Do not fill in the rest of the data.
//
if (SecondaryData->OutBuffer == NULL) {
SecondaryData->Guid = PortBugcheckData->Guid;
SecondaryData->OutBuffer = PortBugcheckData->Buffer;
SecondaryData->OutBufferLength = PortBugcheckData->BufferUsed;
return ;
}
//
// Is there enough space?
//
if (SecondaryData->MaximumAllowed < PortBugcheckData->BufferUsed) {
return ;
}
SecondaryData->Guid = PortBugcheckData->Guid;
SecondaryData->OutBuffer = PortBugcheckData->Buffer;
SecondaryData->OutBufferLength = PortBugcheckData->BufferUsed;
}