/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    atom.c

Abstract:

    WinDbg Extension Api

Author:

    Ramon J San Andres (ramonsa) 5-Nov-1993

Environment:

    User Mode.

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

#define MAXINTATOM 0xC000

VOID
AtomExtension(
    PCSTR lpArgumentString
    );

VOID DumpAtomTable(
    ULONG64 ppat,
    ULONG a
    );

DECLARE_API( atom )

/*++

Routine Description:

    This function is called as an NTSD extension to dump a user mode atom table

    Called as:

        !atom [address]

    If an address if not given or an address of 0 is given, then the
    process atom table is dumped.

Arguments:

    args - [address [detail]]

Return Value:

    None

--*/

{
//    AtomExtension( args );
//                           Copied its code here :-
    ULONG64 ppat, pat;
    ULONG a;
    INIT_API();
    try {
        while (*args == ' ') {
            args++;
        }

        if (*args && *args != 0xa) {
            a = (ULONG) GetExpression((LPSTR)args);
        } else {
            a = 0;
        }

        ppat = GetExpression("kernel32!BaseLocalAtomTable");
        if ((ppat != 0) &&
            ReadPointer(ppat, &pat)) {
            dprintf("\nLocal atom table ");
            DumpAtomTable(ppat, a);
            dprintf("Use 'dt _RTL_ATOM_TABLE %p'.\n", ppat);
        }

    } except (EXCEPTION_EXECUTE_HANDLER) {
        ;
    }
    EXIT_API();
    return S_OK;
}

CHAR szBaseLocalAtomTable[] = "kernel32!BaseLocalAtomTable";

VOID DumpAtomTable(
    ULONG64 ppat,
    ULONG a
    )
{
    ULONG64 pat;
    ULONG64 pate;
    ULONG iBucket, NumberOfBuckets, PtrSize, Off, NameOff;
    LPWSTR pwsz;
    BOOL fFirst;

    ReadPointer(ppat, &pat);
    if (pat == 0) {
        dprintf("is not initialized.\n");
        return;
    }
    
    if (InitTypeRead(pat, _RTL_ATOM_TABLE)) {
        return;
    }
    if (a) {
        dprintf("\n");
    } else {
        dprintf("at %x\n", pat);
    }
    NumberOfBuckets = (ULONG) ReadField(NumberOfBuckets);

    GetFieldOffset("_RTL_ATOM_TABLE", "Buckets", &Off);
    GetFieldOffset("_RTL_ATOM_TABLE", "Name", &NameOff);
    PtrSize = IsPtr64() ? 8 : 4;

    for (iBucket = 0; iBucket < NumberOfBuckets; iBucket++) {
        ReadPointer(pat + iBucket * PtrSize + Off, &pate);
        
        if (pate != 0 && !a) {
            dprintf("Bucket %2d:", iBucket);
        }
        fFirst = TRUE;
        while (pate != 0) {
            ULONG NameLength;

            if (!fFirst && !a) {
                dprintf("          ");
            }
            fFirst = FALSE;
            if (InitTypeRead(pate, _RTL_ATOM_TABLE_ENTRY)) {
                return;
            }
            NameLength = (ULONG) ReadField(NameLength);
            pwsz = (LPWSTR)LocalAlloc(LPTR, ((NameLength) + 1) * sizeof(WCHAR));
            ReadMemory(pate + NameOff, pwsz, NameLength * sizeof(WCHAR), NULL);
            pwsz[NameLength ] = L'\0';
            if (a == 0 || a == ((ULONG)ReadField(HandleIndex) | MAXINTATOM)) {
                dprintf("%hx(%2d) = %ls (%d)%s\n",
                        (ATOM)((ULONG)ReadField(HandleIndex) | MAXINTATOM),
                        (ULONG)ReadField(ReferenceCount),
                        pwsz, (NameLength),
                        (ULONG)ReadField(Flags) & RTL_ATOM_PINNED ? " pinned" : "");

                if (a) {
                    LocalFree(pwsz);
                    return;
                }
            }
            LocalFree(pwsz);
            if (pate == ReadField(HashLink)) {
                dprintf("Bogus hash link at %p\n", pate);
                break;
            }
            pate = ReadField(HashLink);
        }
    }
    if (a)
        dprintf("\n");
}


VOID
AtomExtension(
    PCSTR lpArgumentString
    )
{
    ULONG64 ppat;
    ULONG a;

    try {
        while (*lpArgumentString == ' ') {
            lpArgumentString++;
        }

        if (*lpArgumentString && *lpArgumentString != 0xa) {
            a = (ATOM)GetExpression((LPSTR)lpArgumentString);
        } else {
            a = 0;
        }

        ppat = GetExpression(szBaseLocalAtomTable);
        if (ppat != 0) {
            dprintf("\nLocal atom table ");
            DumpAtomTable(ppat, a);
        }

    } except (EXCEPTION_EXECUTE_HANDLER) {
        ;
    }
}