/*++

Copyright (c) 1992-2000  Microsoft Corporation

Module Name:

    util.c

Abstract:

    WinDbg Extension Api

Environment:

    User Mode.

Revision History:

--*/


#include "precomp.h"
#pragma hdrstop


ULONG
GetBitFieldOffset (
   IN LPSTR     Type, 
   IN LPSTR     Field, 
   OUT PULONG   pOffset,
   OUT PULONG   pSize
   ) 
{ 
   FIELD_INFO flds = {
       Field, "", 0, 
       DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_SIZE_IN_BITS, 
       0, NULL};
   SYM_DUMP_PARAM Sym = {
      sizeof (SYM_DUMP_PARAM), Type, DBG_DUMP_NO_PRINT, 0,
      NULL, NULL, NULL, 1, &flds
   };
   ULONG Err, i=0;
   LPSTR dot, last=Field;
   
   Sym.nFields = 1;
   Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
   *pOffset = (ULONG) (flds.address - Sym.addr);
   *pSize   = flds.size;
   return Err;
}

ULONG
GetUlongFromAddress (
    ULONG64 Location
    )
{
    ULONG Value;
    ULONG result;

    if ((!ReadMemory(Location,&Value,sizeof(ULONG),&result)) ||
        (result < sizeof(ULONG))) {
        dprintf("unable to read from %08x\n",Location);
        return 0;
    }

    return Value;
}

ULONG64
GetPointerFromAddress (
    ULONG64 Location
    )
{
    ULONG64 Value;
    ULONG result;

    if (!ReadPointer(Location,&Value)) {
        dprintf("unable to read from %08p\n",Location);
        return 0;
    }

    return Value;
}

ULONG
GetUlongValue (
    PCHAR String
    )
{
    ULONG64 Location;
    ULONG Value;
    ULONG result;


    Location = GetExpression( String );
    if (!Location) {
        dprintf("unable to get %s\n",String);
        return 0;
    }

    return GetUlongFromAddress( Location );
}


ULONG64
GetPointerValue (
    PCHAR String
    )
{
    ULONG64 Location, Val=0;


    Location = GetExpression( String );
    if (!Location) {
        dprintf("unable to get %s\n",String);
        return 0;
    }

    ReadPointer(Location, &Val);

    return Val;
}
#if 0
VOID
DumpImageName(
    IN ULONG64 Process
    )
{
    ULONG64 ImageFileName;
    STRING String;
    ULONG Result;
    IN WCHAR Buf[512];


    if ( !GetFieldValue(Process, "EPROCESS", "ImageFileName.Buffer", ImageFileName ) ){

        wcscpy(Buf,L"*** image name unavailable ***");
        if ( ReadMemory( ImageFileName,
                         &String,
                         sizeof(STRING),
                         &Result) ) {
            if ( ReadMemory( (DWORD)String.Buffer,
                             &Buf[0],
                             String.Length,
                             &Result) ) {
                Buf[String.Length/sizeof(WCHAR)] = UNICODE_NULL;
            }
        }
    } else {
        wcscpy(Buf,L"System Process");
    }
    dprintf("%ws",Buf);
}
#endif

BOOLEAN
DbgRtlIsRightChild(
    ULONG64 pLinks,
    ULONG64 Parent
    )
{
    ULONG64 RightChild;
    if (Parent == pLinks) {

        return FALSE;
    }

    if (GetFieldValue(Parent, "RTL_SPLAY_LINKS", "RightChild", RightChild)) {

        return FALSE;
    }

    if (RightChild == pLinks) {

        return TRUE;
    }

    return FALSE;
}

BOOLEAN
DbgRtlIsLeftChild(
    ULONG64 pLinks,
    ULONG64 Parent
    )
{
    ULONG64 LeftChild;
    if (Parent == pLinks) {

        return FALSE;
    }

    if (GetFieldValue(Parent, "RTL_SPLAY_LINKS", "LeftChild", LeftChild)) {

        return FALSE;
    }

    if (LeftChild == pLinks) {

        return TRUE;
    }

    return FALSE;
}


ULONG
DumpSplayTree(
    IN ULONG64 pSplayLinks,
    IN PDUMP_SPLAY_NODE_FN DumpNodeFn
    )
/*++
    Purpose:

        Perform an in-order iteration across a splay tree, calling a
        user supplied function with a pointer to each RTL_SPLAY_LINKS
        structure encountered in the tree, and the level in the tree
        at which it was encountered (zero based).

    Arguments:

        pSplayLinks     - pointer to root of a splay tree

        DumpNodeFn      - user supplied dumping function

   Returns:

        Count of nodes encountered in the tree.

   Notes:

        Errors reading memory do not terminate the iteration if more
        work is possible.

        Consumes the Control-C flag to terminate possible loops in
        corrupt structures.

--*/
{
    ULONG Level = 0;
    ULONG NodeCount = 0;

    if (pSplayLinks) {
        ULONG64 LeftChild, RightChild, Parent, Current;

        //
        //  Retrieve the root links, find the leftmost node in the tree
        //

        if (GetFieldValue(Current = pSplayLinks,
                          "RTL_SPLAY_LINKS",
                          "LeftChild",
                          LeftChild)) {

            return NodeCount;
        }

        while (LeftChild != 0) {

            if ( CheckControlC() ) {

                return NodeCount;
            }

            if (GetFieldValue(Current = LeftChild,
                              "RTL_SPLAY_LINKS",
                              "LeftChild",
                              LeftChild)) {

                //
                //  We can try to continue from this
                //

                break;
            }

            Level++;
        }

        while (TRUE) {

            if ( CheckControlC() ) {

                return NodeCount;
            }

            NodeCount++;
            pSplayLinks = Current;
            (*DumpNodeFn)(pSplayLinks, Level);

            /*
                first check to see if there is a right subtree to the input link
                if there is then the real successor is the left most node in
                the right subtree.  That is find and return P in the following diagram

                      Links
                         \
                          .
                         .
                        .
                       /
                      P
                       \
            */

            GetFieldValue(Current, "RTL_SPLAY_LINKS", "RightChild", RightChild);
            if (RightChild != 0) {

                if (GetFieldValue(Current = RightChild,
                                  "RTL_SPLAY_LINKS",
                                  "RightChild",
                                  RightChild)) {

                    //
                    //  We've failed to step through to a successor, so
                    //  there is no more to do
                    //

                    return NodeCount;
                }

                Level++;

                GetFieldValue(Current,"RTL_SPLAY_LINKS","LeftChild",LeftChild);
                while (LeftChild != 0) {

                    if ( CheckControlC() ) {

                        return NodeCount;
                    }

                    if (GetFieldValue(Current = LeftChild,
                                     "RTL_SPLAY_LINKS",
                                     "LeftChild",
                                     LeftChild)) {

                        //
                        //  We can continue from this
                        //

                        break;
                    }

                    Level++;
                }

            } else {

                /*
                    we do not have a right child so check to see if have a parent and if
                    so find the first ancestor that we are a left decendent of. That
                    is find and return P in the following diagram

                               P
                              /
                             .
                              .
                               .
                              Links
                */

                //
                //  If the IsLeft or IsRight functions fail to read through a parent
                //  pointer, then we will quickly exit through the break below
                //

                GetFieldValue(Current, "RTL_SPLAY_LINKS", "Parent", Parent);
                while (DbgRtlIsRightChild(Current, Parent)) {

                    if ( CheckControlC() ) {

                        return NodeCount;
                    }

                    Level--;
                    pSplayLinks = (Current = Parent);
                }

                GetFieldValue(Current, "RTL_SPLAY_LINKS", "Parent", Parent);
                if (!DbgRtlIsLeftChild(Current, Parent)) {

                    //
                    //  we do not have a real successor so we break out
                    //

                    break;

                } else {

                    Level--;
                    pSplayLinks = (Current = Parent);
                }
            }
        }
    }

    return NodeCount;
}

VOID
DumpUnicode64(
    UNICODE_STRING64 u
    )
{
    UNICODE_STRING v;
    DWORD BytesRead;

//    dprintf("L %x, M %x, B %p ", u.Length, u.MaximumLength, u.Buffer);
    if ((u.Length <= u.MaximumLength) &&
        (u.Buffer) &&
        (u.Length > 0)) {

        v.Buffer = LocalAlloc(LPTR, u.MaximumLength);
        if (v.Buffer != NULL) {
            v.MaximumLength = u.MaximumLength;
            v.Length = u.Length;
            if (ReadMemory(u.Buffer,
                           v.Buffer,
                           u.Length,
                           (PULONG) &u.Buffer)) {
                dprintf("%wZ", &v);
            } else {
                dprintf("<???>");
            }
            LocalFree(v.Buffer);

            return;
        }
    }
}

BOOLEAN
IsHexNumber(
   const char *szExpression
   )
{
   if (!szExpression[0]) {
      return FALSE ;
   }

   for(;*szExpression; szExpression++) {
      
      if      ((*szExpression)< '0') { return FALSE ; } 
      else if ((*szExpression)> 'f') { return FALSE ; }
      else if ((*szExpression)>='a') { continue ;     }
      else if ((*szExpression)> 'F') { return FALSE ; }
      else if ((*szExpression)<='9') { continue ;     }
      else if ((*szExpression)>='A') { continue ;     }
      else                           { return FALSE ; }
   }
   return TRUE ;
}


BOOLEAN
IsDecNumber(
   const char *szExpression
   )
{
   if (!szExpression[0]) {
      return FALSE ;
   }

   while(*szExpression) {
      
      if      ((*szExpression)<'0') { return FALSE ; } 
      else if ((*szExpression)>'9') { return FALSE ; }
      szExpression ++ ;
   }
   return TRUE ;
}
