/*++

Copyright (c) 1998-1999 Microsoft Corporation

Module Name:

    debug.h

Abstract:

    This module contains debug-specific declarations.

Author:

    Keith Moore (keithmo)       10-Jun-1998

Revision History:

--*/


#ifndef _DEBUG_H_
#define _DEBUG_H_


#if DBG

//
// Initialization/termination functions.
//

VOID
UlDbgInitializeDebugData(
    VOID
    );

VOID
UlDbgTerminateDebugData(
    VOID
    );

//
// Driver entry/exit notifications.
//

VOID
UlDbgEnterDriver(
    IN PSTR pFunctionName,
    IN PIRP pIrp OPTIONAL,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgLeaveDriver(
    IN PSTR pFunctionName,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

#define UL_ENTER_DRIVER( function, pirp )                                   \
    UlDbgEnterDriver(                                                       \
        (function),                                                         \
        (pirp),                                                             \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UL_LEAVE_DRIVER( function )                                         \
    UlDbgLeaveDriver(                                                       \
        (function),                                                         \
        __FILE__,                                                           \
        __LINE__                                                            \
        )


//
// An instrumented resource.
//

#define MAX_RESOURCE_NAME_LENGTH    64

typedef struct _UL_ERESOURCE
{
    //
    // The actual resource.
    //
    // N.B. This must be the first entry in the structure to make the
    //      debugger extension work properly!
    //

    ERESOURCE Resource;

    //
    // Links onto the global resource list.
    //

    LIST_ENTRY GlobalResourceListEntry;

    //
    // Pointer to the thread that owns this lock exclusively.
    //

    PETHREAD pExclusiveOwner;

    //
    // Statistics.
    //

    LONG ExclusiveCount;
    LONG SharedCount;
    LONG ReleaseCount;

    //
    // The name of the resource, for display purposes.
    //

    UCHAR ResourceName[MAX_RESOURCE_NAME_LENGTH];

} UL_ERESOURCE, *PUL_ERESOURCE;

NTSTATUS
UlDbgInitializeResource(
    IN PUL_ERESOURCE pResource,
    IN PSTR pResourceName,
    IN ULONG_PTR Parameter,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

NTSTATUS
UlDbgDeleteResource(
    IN PUL_ERESOURCE pResource,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

BOOLEAN
UlDbgAcquireResourceExclusive(
    IN PUL_ERESOURCE pResource,
    IN BOOLEAN Wait,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

BOOLEAN
UlDbgAcquireResourceShared(
    IN PUL_ERESOURCE pResource,
    IN BOOLEAN Wait,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgReleaseResource(
    IN PUL_ERESOURCE pResource,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

BOOLEAN
UlDbgResourceOwnedExclusive(
    IN PUL_ERESOURCE pResource
    );

BOOLEAN
UlDbgResourceUnownedExclusive(
    IN PUL_ERESOURCE pResource
    );

#define UlInitializeResource( resource, name, param )                       \
    UlDbgInitializeResource(                                                \
        (resource),                                                         \
        (name),                                                             \
        (ULONG_PTR)(param),                                                 \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlDeleteResource( resource )                                        \
    UlDbgDeleteResource(                                                    \
        (resource),                                                         \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlAcquireResourceExclusive( resource, wait )                        \
    UlDbgAcquireResourceExclusive(                                          \
        (resource),                                                         \
        (wait),                                                             \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlAcquireResourceShared( resource, wait )                           \
    UlDbgAcquireResourceShared(                                             \
        (resource),                                                         \
        (wait),                                                             \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlReleaseResource( resource )                                       \
    UlDbgReleaseResource(                                                   \
        (resource),                                                         \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define IS_RESOURCE_INITIALIZED( resource )                                 \
    ((resource)->Resource.SystemResourcesList.Flink != NULL)


//
// An instrumented spinlock.
//

typedef struct _UL_SPIN_LOCK    // SpinLock
{
    //
    // The actual lock.
    //
    // N.B. This must be the first entry in the structure to make the
    //      debugger extension work properly!
    //

    KSPIN_LOCK KSpinLock;

    //
    // The name of the spinlock, for display purposes.
    //

    PSTR pSpinLockName;

    //
    // Pointer to the thread that owns this lock.
    //

    PETHREAD pOwnerThread;

    //
    // Statistics.
    //

    PSTR pLastAcquireFileName;
    PSTR pLastReleaseFileName;
    USHORT LastAcquireLineNumber;
    USHORT LastReleaseLineNumber;
    ULONG OwnerProcessor;
    LONG Acquisitions;
    LONG Releases;
    LONG AcquisitionsAtDpcLevel;
    LONG ReleasesFromDpcLevel;
    LONG Spare;

} UL_SPIN_LOCK, *PUL_SPIN_LOCK;

#define KSPIN_LOCK_FROM_UL_SPIN_LOCK( pLock )                               \
    &((pLock)->KSpinLock)

VOID
UlDbgInitializeSpinLock(
    IN PUL_SPIN_LOCK pSpinLock,
    IN PSTR pSpinLockName,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgAcquireSpinLock(
    IN PUL_SPIN_LOCK pSpinLock,
    OUT PKIRQL pOldIrql,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgReleaseSpinLock(
    IN PUL_SPIN_LOCK pSpinLock,
    IN KIRQL OldIrql,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgAcquireSpinLockAtDpcLevel(
    IN PUL_SPIN_LOCK pSpinLock,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgReleaseSpinLockFromDpcLevel(
    IN PUL_SPIN_LOCK pSpinLock,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

BOOLEAN
UlDbgSpinLockOwned(
    IN PUL_SPIN_LOCK pSpinLock
    );

BOOLEAN
UlDbgSpinLockUnowned(
    IN PUL_SPIN_LOCK pSpinLock
    );

#define UlInitializeSpinLock( spinlock, name )                              \
    UlDbgInitializeSpinLock(                                                \
        (spinlock),                                                         \
        (name),                                                             \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlAcquireSpinLock( spinlock, oldirql )                              \
    UlDbgAcquireSpinLock(                                                   \
        (spinlock),                                                         \
        (oldirql),                                                          \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlReleaseSpinLock( spinlock, oldirql )                              \
    UlDbgReleaseSpinLock(                                                   \
        (spinlock),                                                         \
        (oldirql),                                                          \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlAcquireSpinLockAtDpcLevel( spinlock )                             \
    UlDbgAcquireSpinLockAtDpcLevel(                                         \
        (spinlock),                                                         \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UlReleaseSpinLockFromDpcLevel( spinlock )                           \
    UlDbgReleaseSpinLockFromDpcLevel(                                       \
        (spinlock),                                                         \
        __FILE__,                                                           \
        __LINE__                                                            \
        )


//
// Debug spew control.
// If you change or add a flag, please update the FlagTable
// in ul\test\dll\tul.c.
//

#undef IF_DEBUG
#define IF_DEBUG(a) if ( (UL_DEBUG_ ## a & g_UlDebug) != 0 )

#define UL_DEBUG_OPEN_CLOSE                 0x00000001
#define UL_DEBUG_SEND_RESPONSE              0x00000002
#define UL_DEBUG_SEND_BUFFER                0x00000004
#define UL_DEBUG_TDI                        0x00000008

#define UL_DEBUG_FILE_CACHE                 0x00000010
#define UL_DEBUG_CONFIG_GROUP_FNC           0x00000020
#define UL_DEBUG_CONFIG_GROUP_TREE          0x00000040
#define UL_DEBUG_REFCOUNT                   0x00000080

#define UL_DEBUG_HTTP_IO                    0x00000100
#define UL_DEBUG_ROUTING                    0x00000200
#define UL_DEBUG_URI_CACHE                  0x00000400
#define UL_DEBUG_PARSER                     0x00000800

#define UL_DEBUG_SITE                       0x00001000
#define UL_DEBUG_WORK_ITEM                  0x00002000

#define UL_DEBUG_PARSER2                    0x80000000

#define DEBUG


//
// Tracing.
//

#define UlTrace(a, _b_)                                                     \
    do                                                                      \
    {                                                                       \
        IF_DEBUG(##a)                                                       \
        {                                                                   \
            DbgPrint _b_ ;                                                  \
        }                                                                   \
    } while (FALSE)


//
// Debug pool allocator.
//

PVOID
UlDbgAllocatePool (
    IN POOL_TYPE PoolType,
    IN SIZE_T NumberOfBytes,
    IN ULONG Tag,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgFreePool (
    IN PVOID pPointer,
    IN ULONG Tag
    );

#define UL_ALLOCATE_POOL( type, len, tag )                                  \
    UlDbgAllocatePool(                                                      \
        (type),                                                             \
        (len),                                                              \
        (tag),                                                              \
        __FILE__,                                                           \
        __LINE__                                                            \
        )

#define UL_FREE_POOL( ptr, tag )                                            \
    UlDbgFreePool(                                                          \
        (ptr),                                                              \
        (tag)                                                               \
        )

//
// Exception filter.
//

LONG
UlDbgExceptionFilter(
    IN PEXCEPTION_POINTERS pExceptionPointers,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

#define UL_EXCEPTION_FILTER()                                               \
    UlDbgExceptionFilter(                                                   \
        GetExceptionInformation(),                                          \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )


//
// Invalid completion routine for catching incomplete IRP contexts.
//

VOID
UlDbgInvalidCompletionRoutine(
    IN PVOID pCompletionContext,
    IN NTSTATUS Status,
    IN ULONG_PTR Information
    );


//
// Error handlers.
//

NTSTATUS
UlDbgStatus(
    IN NTSTATUS Status,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

#define RETURN(status)                                                      \
    return UlDbgStatus(                                                     \
                (status),                                                   \
                __FILE__,                                                   \
                __LINE__                                                    \
                )

#define CHECK_STATUS(status)                                                \
    UlDbgStatus(                                                            \
        (status),                                                           \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )

//
// Random structure dumpers.
//

VOID
UlDbgDumpRequestBuffer(
    IN struct _UL_REQUEST_BUFFER *pBuffer,
    IN PSTR pName
    );

VOID
UlDbgDumpHttpConnection(
    IN struct _HTTP_CONNECTION *pConnection,
    IN PSTR pName
    );


//
// IO wrappers.
//

PIRP
UlDbgAllocateIrp(
    IN CCHAR StackSize,
    IN BOOLEAN ChargeQuota,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgFreeIrp(
    IN PIRP pIrp,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

NTSTATUS
UlDbgCallDriver(
    IN PDEVICE_OBJECT pDeviceObject,
    IN OUT PIRP pIrp,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

VOID
UlDbgCompleteRequest(
    IN PIRP pIrp,
    IN CCHAR PriorityBoost,
    IN PSTR pFileName,
    IN USHORT LineNumber
    );

#define UlAllocateIrp( stack, quota )                                       \
    UlDbgAllocateIrp(                                                       \
        (stack),                                                            \
        (quota),                                                            \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )

#define UlFreeIrp( pirp )                                                   \
    UlDbgFreeIrp(                                                           \
        (pirp),                                                             \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )

#define UlCallDriver( pdevice, pirp )                                       \
    UlDbgCallDriver(                                                        \
        (pdevice),                                                          \
        (pirp),                                                             \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )

#define UlCompleteRequest( pirp, boost )                                    \
    UlDbgCompleteRequest(                                                   \
        (pirp),                                                             \
        (boost),                                                            \
        (PSTR)__FILE__,                                                     \
        (USHORT)__LINE__                                                    \
        )

#else   // !DBG

//
// Disable all of the above.
//

#define UL_ENTER_DRIVER( function, pirp )
#define UL_LEAVE_DRIVER( function )

#define UL_ERESOURCE ERESOURCE
#define PUL_ERESOURCE PERESOURCE

#define UlInitializeResource( resource, name, param )                       \
    ExInitializeResource( (resource) )

#define UlDeleteResource( resource )                                        \
    ExDeleteResource( (resource) )

#define UlAcquireResourceExclusive( resource, wait )                        \
    do                                                                      \
    {                                                                       \
        KeEnterCriticalRegion();                                            \
        ExAcquireResourceExclusive( (resource), (wait) );                   \
    } while (FALSE)

#define UlAcquireResourceShared( resource, wait )                           \
    do                                                                      \
    {                                                                       \
        KeEnterCriticalRegion();                                            \
        ExAcquireResourceShared( (resource), (wait) );                      \
    } while (FALSE)

#define UlReleaseResource( resource )                                       \
    do                                                                      \
    {                                                                       \
        ExReleaseResource( (resource) );                                    \
        KeLeaveCriticalRegion();                                            \
    } while (FALSE)

#define IS_RESOURCE_INITIALIZED( resource )                                 \
    ((resource)->SystemResourcesList.Flink != NULL)

#define UL_SPIN_LOCK KSPIN_LOCK
#define PUL_SPIN_LOCK PKSPIN_LOCK

#define KSPIN_LOCK_FROM_UL_SPIN_LOCK( pLock ) (pLock)

#define UlInitializeSpinLock( spinlock, name )                              \
    KeInitializeSpinLock( (spinlock) )

#define UlAcquireSpinLock( spinlock, oldirql )                              \
    KeAcquireSpinLock( (spinlock), (oldirql) )

#define UlReleaseSpinLock( spinlock, oldirql )                              \
    KeReleaseSpinLock( (spinlock), (oldirql) )

#define UlAcquireSpinLockAtDpcLevel( spinlock )                             \
    KeAcquireSpinLockAtDpcLevel( (spinlock) )

#define UlReleaseSpinLockFromDpcLevel( spinlock )                           \
    KeReleaseSpinLockFromDpcLevel( (spinlock) )

#undef IF_DEBUG
#define IF_DEBUG(a) if (FALSE)
#define DEBUG if ( FALSE )

#define UlTrace(a, _b_)

#define UL_ALLOCATE_POOL( type, len, tag )                                  \
    ExAllocatePoolWithTag(                                                  \
        (type),                                                             \
        (len),                                                              \
        (tag)                                                               \
        )

#define UL_FREE_POOL( ptr, tag )                                            \
    MyFreePoolWithTag(                                                      \
        (ptr),                                                              \
        (tag)                                                               \
        )

#define UL_EXCEPTION_FILTER() EXCEPTION_EXECUTE_HANDLER

#define RETURN(status) return (status)
#define CHECK_STATUS(Status)

#define UlAllocateIrp( stack, quota )                                       \
    IoAllocateIrp( (stack), (quota) )

#define UlFreeIrp( pirp )                                                   \
    IoFreeIrp( (pirp) )

#define UlCallDriver( pdevice, pirp )                                       \
    IoCallDriver( (pdevice), (pirp) )

#define UlCompleteRequest( pirp, boost )                                    \
    IoCompleteRequest( (pirp), (boost) )

#endif  // DBG

// BUGBUG: ALIGN_UP(PVOID) won't work, it needs to be the type of the first entry of the
// following data (paulmcd 4/29/99)

#define UL_ALLOCATE_STRUCT_WITH_SPACE(pt,ot,cb,t)   \
    (ot *)(UL_ALLOCATE_POOL(pt,ALIGN_UP(sizeof(ot),PVOID)+(cb),t))

#define UL_ALLOCATE_STRUCT(pt,ot,t)                 \
    (ot *)(UL_ALLOCATE_POOL(pt,sizeof(ot),t))

#define UL_ALLOCATE_ARRAY(pt,et,c,t)                \
    (et *)(UL_ALLOCATE_POOL(pt,sizeof(et)*(c),t))

#define UL_FREE_POOL_WITH_SIG(a,t)                  \
    do {                                            \
        (a)->Signature = MAKE_FREE_TAG(t);          \
        UL_FREE_POOL(a,t);                          \
        (a) = NULL;                                 \
    } while (0)

#endif  // _DEBUG_H_