/* (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl>
 * Web: http://www.xs4all.nl/~itsme/
 *      http://wiki.xda-developers.com/
 *
 * $Id: $
 *
 * tool to dump info from a handle
 */
#include <util/wintypes.h>
#include "itsutils.h"
#include "dllversion.h"
#include "debug.h"
#include "args.h"
#include <stdio.h>
#include <string.h>
#include <util/rapitypes.h>

#include <string>
#include <map>
#include "stringutils.h"
#include "ptrutils.h"

bool ITReadProcessMemory(HANDLE hProc, DWORD dwOffset, BYTE *buffer, DWORD dwBytesWanted, DWORD *pdwNumberOfBytesRead)
{
    ReadProcessMemoryParams inbuf;
    DWORD outsize=0;
    ReadProcessMemoryResult *outbuf=NULL;

    inbuf.hProcess= hProc;
    inbuf.dwOffset= dwOffset;
    inbuf.nSize= dwBytesWanted;
    inbuf.nDataAccess= 0;
    outbuf= NULL; outsize= 0;
    HRESULT res= ItsutilsInvoke("ITReadProcessMemory",
            sizeof(ReadProcessMemoryParams), (BYTE*)&inbuf,
            &outsize, (BYTE**)&outbuf);
    if (res || outbuf==NULL)
    {
        error((DWORD)res, "ITReadProcessMemory");
        return false;
    }
    memcpy(buffer, &outbuf->buffer, outbuf->dwNumberOfBytesRead);
    *pdwNumberOfBytesRead= outbuf->dwNumberOfBytesRead;
    RapiFree(outbuf);

    return true;
}
HANDLE ITGetProcessHandle(const std::string& processName)
{
    std::Wstring wstr= ToWString(processName);
    DWORD insize= (wstr.size()+1)*sizeof(WCHAR);
    WCHAR *inbuf= (WCHAR*)RapiAlloc(insize);

    memcpy(inbuf, &wstr[0], insize);

    inbuf[wstr.size()]= 0;

    DWORD outsize=0;
    HANDLE *outbuf=NULL;

    HRESULT res= ItsutilsInvoke("ITGetProcessHandle",
            insize, (BYTE*)inbuf,
            &outsize, (BYTE**)&outbuf);
    if (res || outbuf==NULL) 
    {
        error(res, "ITGetProcessHandle");
        return INVALID_HANDLE_VALUE;
    }

    HANDLE hproc= *outbuf;

    RapiFree(outbuf);

    return hproc;
}
DWORD ReadDword(DWORD dwOffset)
{
    DWORD nRead;
    DWORD dwValue;
    if (!ITReadProcessMemory(NULL, dwOffset, (BYTE*)&dwValue, sizeof(DWORD), &nRead))
        return 0;
    return dwValue;
}

#define DECLARE_CACHED_STRUCT(type, readfunc, mapvar) \
typedef std::map <type##PTR,type> Ptr##type##Map; \
Ptr##type##Map mapvar; \
bool readfunc(type##PTR hdp, type **phd) \
{ \
    Ptr##type##Map::iterator i= mapvar.find(hdp); \
    if (i!=mapvar.end()) { \
        *phd = & (*i).second; \
        return true; \
    } \
    *phd= & mapvar[hdp]; \
    DWORD nRead; \
    if (!ITReadProcessMemory(0, hdp, (BYTE*)*phd, sizeof(type), &nRead)) \
        return false; \
 \
    return true; \
}

// c:\local\wince500\PRIVATE\WINCEOS\COREOS\NK\INC\schedule.h
// c:\local\wince500\PRIVATE\WINCEOS\COREOS\NK\INC\kernel.h
// c:/local/wince500/PRIVATE/WINCEOS/COREOS/NK/INC/nkarm.h
typedef DWORD ACCESSKEY;
typedef DWORD RETADDR;
typedef DWORD CLEANEVENTPTR;
typedef DWORD PROXYPTR;
typedef DWORD THREADPTR;
typedef DWORD ModulePTR;
typedef DWORD NamePTR;
typedef DWORD APISETARRAYPTR;
typedef DWORD EVENTPTR;
typedef DWORD KHEAPARRAYPTR;
typedef DWORD MEMINFOPTR;
typedef DWORD MODULELISTPTR;
typedef DWORD MODULEPTR;
typedef DWORD ROMHDRPTR;
typedef DWORD SECTIONARRAYPTR;
typedef DWORD SECTIONPTR;
typedef DWORD PROCESSPTR;
typedef DWORD THRDDBGPTR;
typedef DWORD CRITPTR;
typedef DWORD WSTRPTR;
typedef DWORD o32_litePTR;
typedef DWORD CALLSTACKPTR;
typedef DWORD DTHREADPTR;
typedef DWORD CINFOPTR;
typedef DWORD HDATAPTR;
typedef DWORD PROCESSARRAYPTR;
typedef DWORD BYTEPTR;

typedef struct {
    ULONG Psr;
    ULONG R0;
    ULONG R1;
    ULONG R2;
    ULONG R3;
    ULONG R4;
    ULONG R5;
    ULONG R6;
    ULONG R7;
    ULONG R8;
    ULONG R9;
    ULONG R10;
    ULONG R11;
    ULONG R12;
    ULONG Sp;
    ULONG Lr;
    ULONG Pc;

    // VFP registers
    ULONG Fpscr;        // floating point status register
    ULONG FpExc;        // the exception register
#define NUM_VFP_REGS            32
    ULONG S[NUM_VFP_REGS+1];    // fstmx/fldmx requires n+1 registers
#define NUM_EXTRA_CONTROL_REGS 8
    ULONG FpExtra[NUM_EXTRA_CONTROL_REGS];

} CPUCONTEXT;

typedef struct {
    WCHAR str[260];
} WSTR;
DECLARE_CACHED_STRUCT(WSTR, ReadWString, pwsmap)

typedef struct {
    DWORD handle;     // 0x00     // object store handle
    BYTE filetype;    // 0x04
    BYTE bIsOID;      // 0x05
    WORD pagemode;    // 0x06
    DWORD offset;     // 0x08
    NamePTR name;     // 0x0c
} openexe_t;
typedef struct {
    DWORD rva;             // 0x00 /* Virtual relative address of info    */
    DWORD size;            // 0x04 /* Size of information block           */
} info;
typedef struct {
    WORD e32_objcnt;       // 0x00 /* Number of memory objects            */
    BYTE e32_cevermajor;   // 0x02 /* version of CE built for             */
    BYTE e32_ceverminor;   // 0x03 /* version of CE built for             */
    DWORD e32_stackmax;    // 0x04 /* Maximum stack size                  */
    DWORD e32_vbase;       // 0x08 /* Virtual base address of module      */
    DWORD e32_vsize;       // 0x0c /* Virtual size of the entire image    */
    DWORD e32_sect14rva;   // 0x10 /* section 14 rva */
    DWORD e32_sect14size;  // 0x14 /* section 14 size */
    info e32_unit[6];      // 0x18 /* Array of extra info units   */
} e32_lite420;
typedef struct {
    WORD e32_objcnt;       // 0x00 /* Number of memory objects            */
    BYTE e32_cevermajor;   // 0x02 /* version of CE built for             */
    BYTE e32_ceverminor;   // 0x03 /* version of CE built for             */
    DWORD e32_stackmax;    // 0x04 /* Maximum stack size                  */
    DWORD e32_vbase;       // 0x08 /* Virtual base address of module      */
    DWORD e32_vsize;       // 0x0c /* Virtual size of the entire image    */
    DWORD e32_sect14rva;   // 0x10 /* section 14 rva */
    DWORD e32_sect14size;  // 0x14 /* section 14 size */
    DWORD e32_timestamp;   // 0x18 /* wce5: Time EXE/DLL was created/modified   */
    info e32_unit[7];      // 0x1c /* Array of extra info units     */
} e32_lite500;
typedef struct {
    DWORD o32_vsize;         // 0x00
    DWORD o32_rva;           // 0x04
    DWORD o32_realaddr;      // 0x08
    DWORD o32_access;        // 0x0c
    DWORD o32_flags;         // 0x10
    DWORD o32_psize;         // 0x14
    DWORD o32_dataptr;       // 0x18
} o32_lite;
typedef e32_lite500 e32_lite;

typedef struct {
    CALLSTACKPTR pcstkNext; // 00
    RETADDR     retAddr;    /* 04: return address */
    PROCESSPTR  pprcLast; /* 08: previous process */
    ACCESSKEY   akyLast;    /* 0c: previous access key */
    DWORD       extra;      /* 10: extra CPU dependent data */
    DWORD       dwPrevSP;   /* 14: SP of caller */
    DWORD       dwPrcInfo;  /* 18: information about the caller (mode, callback?, etc) */
} CALLSTACK;
DECLARE_CACHED_STRUCT(CALLSTACK, ReadCallstack, pcallstackmap)

typedef struct {
    WORD        wInfo;      /* 00: various info about thread, see above */
    BYTE        bSuspendCnt;/* 02: thread suspend count */
    BYTE        bWaitState; /* 03: state of waiting loop */
    PROXYPTR     pProxList;  /* 04: list of proxies to threads blocked on this thread */
    THREADPTR     pNextInProc;/* 08: next thread in this process */
    PROCESSPTR    pProc;      /* 0C: pointer to current process */
    PROCESSPTR    pOwnerProc; /* 10: pointer to owner process */
    ACCESSKEY   aky;        /* 14: keys used by thread to access memory & handles */
    CALLSTACKPTR  pcstkTop;   /* 18: current api call info */
    DWORD       dwOrigBase; /* 1C: Original stack base */
    DWORD       dwOrigStkSize;  /* 20: Size of the original thread stack */
    LPDWORD     tlsPtr;     /* 24: tls pointer */
    DWORD       dwWakeupTime; /* 28: sleep count, also pending sleepcnt on waitmult */
    LPDWORD     tlsSecure;      /* 2c: TLS for secure stack */
    LPDWORD     tlsNonSecure;   /* 30: TLS for non-secure stack */
    PROXYPTR     lpProxy;    /* 34: first proxy this thread is blocked on */
    DWORD       dwLastError;/* 38: last error */
    HANDLE      hTh;        /* 3C: Handle to this thread, needed by NextThread */
    BYTE        bBPrio;     /* 40: base priority */
    BYTE        bCPrio;     /* 41: curr priority */
    WORD        wCount;     /* 42: nonce for blocking lists */
    THREADPTR     pPrevInProc;/* 44: previous thread in this process */
    THRDDBGPTR   pThrdDbg;   /* 48: pointer to thread debug structure, if any */
    LPBYTE      pSwapStack; /* 4c */
    FILETIME    ftCreate;   /* 50: time thread is created */
    CLEANEVENTPTR lpce;       /* 58: cleanevent for unqueueing blocking lists */
    DWORD       dwStartAddr; /* 5c: thread PC at creation, used to get thread name */
    CPUCONTEXT  ctx;        /* 60: thread's cpu context information */
    THREADPTR    pNextSleepRun; /* 150: next sleeping thread, if sleeping, else next on runq if runnable */
    THREADPTR    pPrevSleepRun; /* 154: back pointer if sleeping or runnable */
    THREADPTR    pUpRun;     /* 158: up run pointer (circulaar) */
    THREADPTR    pDownRun;   /* 15c: down run pointer (circular) */
    THREADPTR    pUpSleep;   /* 160: up sleep pointer (null terminated) */
    THREADPTR    pDownSleep; /* 164: down sleep pointer (null terminated) */
    CRITPTR     pOwnedList; /* 168: list of crits and mutexes for priority inversion */
#define PRIORITY_LEVELS_HASHSIZE 32
    CRITPTR     pOwnedHash[PRIORITY_LEVELS_HASHSIZE];   // 16c
    DWORD       dwQuantum;  /* 1ec: thread quantum */
    DWORD       dwQuantLeft;/* 1f0: quantum left */
    PROXYPTR    lpCritProxy;/* 1f4: proxy from last critical section block, in case stolen back */
    PROXYPTR    lpPendProxy;/* 1f8: pending proxies for queueing */
    DWORD       dwPendReturn;/* 1fc: return value from pended wait */
    DWORD       dwPendTime; /* 200: timeout value of wait operation */
    THREADPTR     pCrabPth; // 204
    WORD        wCrabCount; // 208
    WORD        wCrabDir;   // 20a
    DWORD       dwPendWakeup;/* 20c: pending timeout */
    WORD        wCount2;    /* 210: nonce for SleepList */
    BYTE        bPendSusp;  /* 212: pending suspend count */
    BYTE        bDbgCnt;    /* 213: recurse level in debug message */
    HANDLE      hLastCrit;  /* 214: Last crit taken, cleared by nextthread */
    //DWORD     dwCrabTime;
    CALLSTACK   IntrStk;    // 218
    DWORD       dwKernTime; /* 234: elapsed kernel time */
    DWORD       dwUserTime; /* 238: elapsed user time */
    HANDLE      hTok;       /* 23c: thread token  --  new in wce5*/
} THREAD500;
typedef THREAD500 THREAD;
DECLARE_CACHED_STRUCT(THREAD, ReadThread, pthreadmap)



typedef struct {
    WORD idxHead;
    WORD idxTail;
} PGPOOL_Q;
typedef struct {
    BYTE procnum;                /* 00: ID of this process [ie: it's slot number] */
    BYTE DbgActive;              /* 01: ID of process currently DebugActiveProcess'ing this process */
    BYTE bChainDebug;            /* 02: Did the creator want to debug child processes? */
    BYTE bTrustLevel;            /* 03: level of trust of this exe */
    PROXYPTR pProxList;          /* 04: list of proxies to threads blocked on this process */
    DWORD hProc;                 /* 08: handle for this process, needed only for SC_GetProcFromPtr */
    DWORD dwVMBase;              /* 0C: base of process's memory section, or 0 if not in use */
    THREADPTR pTh;               /* 10: first thread in this process */
    DWORD aky;                   /* 14: default address space key for process's threads */
    DWORD BasePtr;               /* 18: Base pointer of exe load */
    DWORD hDbgrThrd;             /* 1C: handle of thread debugging this process, if any */
    WSTRPTR lpszProcName;        /* 20: name of process */
    DWORD tlsLowUsed;            /* 24: TLS in use bitmask (first 32 slots) */
    DWORD tlsHighUsed;           /* 28: TLS in use bitmask (second 32 slots) */
    DWORD pfnEH;                 /* 2C: process exception handler */
    DWORD ZonePtr;               /* 30: Debug zone pointer */
    THREADPTR pMainTh;           /* 34  primary thread in this process*/
    ModulePTR pmodResource;      /* 38: module that contains the resources */
    NamePTR pStdNames[3];        /* 3C: Pointer to names for stdio */
    WSTRPTR pcmdline;            /* 48: Pointer to command line */
    DWORD dwDyingThreads;       /* 4C: number of pending dying threads */
    openexe_t oe;               /* 50: Pointer to executable file handle */
    e32_lite420 e32;               /* 60: structure containing exe header */
    o32_litePTR o32_ptr;        /* a8: o32 array pointer for exe */
    DWORD pExtPdata;            /* ac: extend pdata */
    BYTE bPrio;                 /* b0: highest priority of all threads of the process */
    BYTE fNoDebug;              /* b1: this process cannot be debugged */
    WORD wPad;                  /* b2: padding */
    PGPOOL_Q  pgqueue;          /* b4: list of the page owned by the process */
} PROCESS420;
typedef struct {
    BYTE procnum;                /* 00: ID of this process [ie: it's slot number] */
    BYTE DbgActive;              /* 01: ID of process currently DebugActiveProcess'ing this process */
    BYTE bChainDebug;            /* 02: Did the creator want to debug child processes? */
    BYTE bTrustLevel;            /* 03: level of trust of this exe */
    PROXYPTR pProxList;          /* 04: list of proxies to threads blocked on this process */
    DWORD hProc;                 /* 08: handle for this process, needed only for SC_GetProcFromPtr */
    DWORD dwVMBase;              /* 0C: base of process's memory section, or 0 if not in use */
    THREADPTR pTh;               /* 10: first thread in this process */
    DWORD aky;                   /* 14: default address space key for process's threads */
    DWORD BasePtr;               /* 18: Base pointer of exe load */
    DWORD hDbgrThrd;             /* 1C: handle of thread debugging this process, if any */
    WSTRPTR lpszProcName;        /* 20: name of process */
    DWORD tlsLowUsed;            /* 24: TLS in use bitmask (first 32 slots) */
    DWORD tlsHighUsed;           /* 28: TLS in use bitmask (second 32 slots) */
    DWORD pfnEH;                 /* 2C: process exception handler */
    DWORD ZonePtr;               /* 30: Debug zone pointer */
    THREADPTR pMainTh;           /* 34  primary thread in this process*/
    ModulePTR pmodResource;      /* 38: module that contains the resources */
    NamePTR pStdNames[3];        /* 3C: Pointer to names for stdio */
    WSTRPTR pcmdline;            /* 48: Pointer to command line */
    DWORD dwDyingThreads;       /* 4C: number of pending dying threads */
    openexe_t oe;               /* 50: Pointer to executable file handle */
    e32_lite500 e32;            /* 60: structure containing exe header */
    o32_litePTR o32_ptr;        /* b4: o32 array pointer for exe */
    DWORD pExtPdata;            /* b8: extend pdata */
    BYTE bPrio;                 /* bc: highest priority of all threads of the process */
    BYTE fNoDebug;              /* bd: this process cannot be debugged */
    WORD wModCount;             /* be: padding */
    PGPOOL_Q  pgqueue;          /* c0: list of the page owned by the process */
    MODULELISTPTR pLastModList;   /* c4: the list of modules that just loaded/unloaded into the process */
    HANDLE      hTok;           /* c8: process default token */
#define HARDWARE_PT_PER_PROC 8
    DWORD       pPTBL[HARDWARE_PT_PER_PROC];   /* cc: hardware page tables */
    LPVOID      pShimInfo;      /* ec: pointer to shim information */
} PROCESS500;
typedef PROCESS500 PROCESS;
DECLARE_CACHED_STRUCT(PROCESS, ReadProcess, pprocmap)

typedef struct {
    PROXYPTR pQPrev;
    PROXYPTR pQNext;
    PROXYPTR pQUp;
    PROXYPTR pQDown;
    PROXYPTR pThLinkNext;
    BYTEPTR  pObject;
    BYTE bType;
    BYTE prio;
    WORD wCount;
    THREADPTR pTh;
    DWORD dwRetVal;
} PROXY;
DECLARE_CACHED_STRUCT(PROXY, ReadProxy, pproxmap)

typedef struct {
    char acName[4];     // 00
    BYTE disp;          // 04
    BYTE type;          // 05
    WORD cMethods;      // 06
    DWORD ppfnMethods;  // 08
    DWORD pdwSig;       // 0c
    PROCESSPTR pServer; // 10
} CINFO;
DECLARE_CACHED_STRUCT(CINFO, ReadCInfo, pcimap)

typedef struct {
    DWORD fwd;      // 00
    DWORD back;     // 04
    DWORD hValue;   // 08
    DWORD lock;     // 0c
    DWORD ref;      // 10
    CINFOPTR pci;   // 14
    DWORD pvObj;    // 18
    DWORD dwInfo;   // 1c
} HDATA;
DECLARE_CACHED_STRUCT(HDATA, ReadHData, phdmap)

typedef struct {
    HANDLE hNext;           /* 00 Next event in list */
    PROXYPTR pProxList;      // 04
    PROXYPTR pProxHash[PRIORITY_LEVELS_HASHSIZE];    // 08
    HANDLE hPrev;           /* 88 previous event in list */
    BYTE onequeue;          // 8c
    BYTE state;             /* 8d TRUE: signalled, FALSE: unsignalled */
    BYTE manualreset;       /* 8e TRUE: manual reset, FALSE: autoreset */
    BYTE bMaxPrio;          // 8f
    NamePTR name;             /* 90 points to name of event */
    PROXYPTR pIntrProxy;     // 94
    DWORD dwData;           /* 98 data associated with the event (CE extention) */
} EVENT;
DECLARE_CACHED_STRUCT(EVENT, ReadEvent, pevmap)

typedef struct {
    DWORD lpvTls;              // 0xFFFFC800 Current thread local storage pointer
    DWORD ahSys[32];           // 0xFFFFC804 
    //DWORD ahSys_W32;           // 0xFFFFC804 
    //DWORD hCurThread;          // 0xFFFFC808 
    //DWORD hCurProc;            // 0xFFFFC80C 
    BYTE bResched;            // 0xFFFFC884 reschedule flag
    BYTE cNest;               // 0xFFFFC885 kernel exception nesting
    BYTE bPowerOff;           // 0xFFFFC886 TRUE during "power off" processing
    BYTE bProfileOn;          // 0xFFFFC887 TRUE if profiling enabled
    DWORD unused;              // 0xFFFFC888 
    DWORD rsvd2;               // 0xFFFFC88C was DiffMSec
    PROCESSPTR pCurPrc;        // 0xFFFFC890 ptr to current PROCESS struct
    THREADPTR pCurThd;         // 0xFFFFC894 ptr to current THREAD struct
    DWORD dwKCRes;             // 0xFFFFC898 
    DWORD handleBase;          // 0xFFFFC89C handle table base address
    SECTIONPTR aSections[64];  // 0xFFFFC8A0 section table for virutal memory
    EVENTPTR alpeIntrEvents[32];// 0xFFFFC9A0 
    EVENTPTR alpvIntrData[32]; // 0xFFFFCA20 
    DWORD pAPIReturn;          // 0xFFFFCAA0 direct API return address for kernel mode
    DWORD pMap;                // 0xFFFFCAA4 ptr to MemoryMap array
    DWORD dwInDebugger;        // 0xFFFFCAA8 !0 when in debugger
    DTHREADPTR pCurFPUOwner;   // 0xFFFFCAAC current FPU owner
    PROCESSPTR pCpuASIDPrc;    // 0xFFFFCAB0 current ASID proc
    DWORD nMemForPT;           // 0xFFFFCAB4 Memory used for PageTables
    DWORD alPad[18];           // 0xFFFFCAB8 
    PROCESSARRAYPTR KINX_PROCARRAY;      // 0xFFFFCB00 address of process array
    DWORD KINX_PAGESIZE;       // 0xFFFFCB04 system page size
    DWORD KINX_PFN_SHIFT;      // 0xFFFFCB08 shift for page # in PTE
    DWORD KINX_PFN_MASK;       // 0xFFFFCB0C mask for page # in PTE
    DWORD KINX_PAGEFREE;       // 0xFFFFCB10 # of free physical pages
    DWORD KINX_SYSPAGES;       // 0xFFFFCB14 # of pages used by kernel
    KHEAPARRAYPTR KINX_KHEAP;          // 0xFFFFCB18 ptr to kernel heap array
    SECTIONARRAYPTR KINX_SECTIONS;       // 0xFFFFCB1C ptr to SectionTable array
    MEMINFOPTR KINX_MEMINFO;        // 0xFFFFCB20 ptr to system MemoryInfo struct
    MODULEPTR KINX_MODULES;        // 0xFFFFCB24 ptr to module list
    DWORD KINX_DLL_LOW;        // 0xFFFFCB28 lower bound of DLL shared space
    DWORD KINX_NUMPAGES;       // 0xFFFFCB2C total # of RAM pages
    ROMHDRPTR KINX_PTOC;           // 0xFFFFCB30 ptr to ROM table of contents       points to ROMHDR struct
    DWORD KINX_KDATA_ADDR;     // 0xFFFFCB34 kernel mode version of KData
    DWORD KINX_GWESHEAPINFO;   // 0xFFFFCB38 Current amount of gwes heap in use
    DWORD KINX_TIMEZONEBIAS;   // 0xFFFFCB3C Fast timezone bias info
    DWORD KINX_PENDEVENTS;     // 0xFFFFCB40 bit mask for pending interrupt events
    DWORD KINX_KERNRESERVE;    // 0xFFFFCB44 number of kernel reserved pages
    DWORD KINX_API_MASK;       // 0xFFFFCB48 bit mask for registered api sets
    DWORD KINX_NLS_CP;         // 0xFFFFCB4C hiword OEM code page, loword ANSI code page
    DWORD KINX_NLS_SYSLOC;     // 0xFFFFCB50 Default System locale
    DWORD KINX_NLS_USERLOC;    // 0xFFFFCB54 Default User locale
    DWORD KINX_HEAP_WASTE;     // 0xFFFFCB58 Kernel heap wasted space
    DWORD KINX_DEBUGGER;       // 0xFFFFCB5C For use by debugger for protocol communication
    APISETARRAYPTR KINX_APISETS;        // 0xFFFFCB60 APIset pointers
    DWORD KINX_MINPAGEFREE;    // 0xFFFFCB64 water mark of the minimum number of free pages
    DWORD KINX_CELOGSTATUS;    // 0xFFFFCB68 CeLog status flags
    SECTIONPTR KINX_NKSECTION; // 0xFFFFCB6C Address of NKSection
    DWORD KINX_PTR_CURTOKEN;   // 0xFFFFCB70 Events to be set after power on
    DWORD KINX_TIMECHANGECOUNT;// 0xFFFFCB74 # of times time changed
    DWORD KINX_30;             // 0xFFFFCB78 
    DWORD KINX_NKSIG;          // 0xFFFFCB7C last entry of KINFO -- signature when NK is ready
} KData;
KData kd;
bool ReadKData()
{
    DWORD nRead=0;
    if (!ITReadProcessMemory(0, 0xFFFFC800, (BYTE*)&kd, sizeof(KData), &nRead))
        return false;
    return true;
}
bool dumpapiptrs()
{
    CINFOPTR apiptrs[256];
    DWORD nRead=0;
    if (!ITReadProcessMemory(0, kd.KINX_APISETS, (BYTE*)apiptrs, sizeof(apiptrs), &nRead)) {
        return false;
    }
    for (unsigned i=0 ; i<0x100  ; i++)
    {
        if (apiptrs[i]==0)
            continue;
        CINFO *ci;
        if (ReadCInfo(apiptrs[i], &ci))
            printf("  %08lx api %02x %c%c%c%c %02x/%02x  proc=%08lx  nmeth=%d\n", apiptrs[i], i,
                ci->acName[0], ci->acName[1], ci->acName[2], ci->acName[3]?ci->acName[3]:' ',
                ci->disp, ci->type, ci->pServer, ci->cMethods);
    }
    return true;
}
void DumpKData()
{
    printf("0xFFFFC800 : %08lx  DWORD lpvTls\n", kd.lpvTls);
    printf("0xFFFFC804 : %08lx  HANDLE ahSys_W32\n", kd.ahSys[0]);
    printf("0xFFFFC808 : %08lx  HANDLE hCurThread\n", kd.ahSys[1]);
    printf("0xFFFFC80C : %08lx  HANDLE hCurProc\n", kd.ahSys[2]);
    printf("0xFFFFC884 : %08lx  BYTE bResched\n", kd.bResched);
    printf("0xFFFFC885 : %08lx  BYTE cNest\n", kd.cNest);
    printf("0xFFFFC886 : %08lx  BYTE bPowerOff\n", kd.bPowerOff);
    printf("0xFFFFC887 : %08lx  BYTE bProfileOn\n", kd.bProfileOn);
    printf("0xFFFFC888 : %08lx  DWORD unused\n", kd.unused);
    printf("0xFFFFC88C : %08lx  DWORD rsvd2\n", kd.rsvd2);
    printf("0xFFFFC890 : %08lx  PROCESSPTR pCurPrc\n", kd.pCurPrc);
    printf("0xFFFFC894 : %08lx  THREADPTR pCurThd\n", kd.pCurThd);
    printf("0xFFFFC898 : %08lx  DWORD dwKCRes\n", kd.dwKCRes);
    printf("0xFFFFC89C : %08lx  DWORD handleBase\n", kd.handleBase);
//  SECTIONPTR aSections[64];  // 0xFFFFC8A0 section table for virutal memory
//  EVENTPTR alpeIntrEvents[32];// 0xFFFFC9A0 
//  EVENTPTR alpvIntrData[32]; // 0xFFFFCA20 
    printf("0xFFFFCAA0 : %08lx  DWORD pAPIReturn\n", kd.pAPIReturn);
    printf("0xFFFFCAA4 : %08lx  DWORD pMap\n", kd.pMap);
    printf("0xFFFFCAA8 : %08lx  DWORD dwInDebugger\n", kd.dwInDebugger);
    printf("0xFFFFCAAC : %08lx  DTHREADPTR pCurFPUOwner\n", kd.pCurFPUOwner);
    printf("0xFFFFCAB0 : %08lx  PROCESSPTR pCpuASIDPrc\n", kd.pCpuASIDPrc);
    printf("0xFFFFCAB4 : %08lx  DWORD nMemForPT\n", kd.nMemForPT);
//  DWORD alPad[18];           // 0xFFFFCAB8 
    printf("0xFFFFCB00 : %08lx  PROCESSARRAYPTR KINX_PROCARRAY\n", kd.KINX_PROCARRAY);
    printf("0xFFFFCB04 : %08lx  DWORD KINX_PAGESIZE\n", kd.KINX_PAGESIZE);
    printf("0xFFFFCB08 : %08lx  DWORD KINX_PFN_SHIFT\n", kd.KINX_PFN_SHIFT);
    printf("0xFFFFCB0C : %08lx  DWORD KINX_PFN_MASK\n", kd.KINX_PFN_MASK);
    printf("0xFFFFCB10 : %08lx  DWORD KINX_PAGEFREE\n", kd.KINX_PAGEFREE);
    printf("0xFFFFCB14 : %08lx  DWORD KINX_SYSPAGES\n", kd.KINX_SYSPAGES);
    printf("0xFFFFCB18 : %08lx  KHEAPARRAYPTR KINX_KHEAP\n", kd.KINX_KHEAP);
    printf("0xFFFFCB1C : %08lx  SECTIONARRAYPTR KINX_SECTIONS\n", kd.KINX_SECTIONS);
    printf("0xFFFFCB20 : %08lx  MEMINFOPTR KINX_MEMINFO\n", kd.KINX_MEMINFO);
    printf("0xFFFFCB24 : %08lx  MODULEPTR KINX_MODULES\n", kd.KINX_MODULES);
    printf("0xFFFFCB28 : %08lx  DWORD KINX_DLL_LOW\n", kd.KINX_DLL_LOW);
    printf("0xFFFFCB2C : %08lx  DWORD KINX_NUMPAGES\n", kd.KINX_NUMPAGES);
    printf("0xFFFFCB30 : %08lx  ROMHDRPTR KINX_PTOC\n", kd.KINX_PTOC);
    printf("0xFFFFCB34 : %08lx  DWORD KINX_KDATA_ADDR\n", kd.KINX_KDATA_ADDR);
    printf("0xFFFFCB38 : %08lx  DWORD KINX_GWESHEAPINFO\n", kd.KINX_GWESHEAPINFO);
    printf("0xFFFFCB3C : %08lx  DWORD KINX_TIMEZONEBIAS\n", kd.KINX_TIMEZONEBIAS);
    printf("0xFFFFCB40 : %08lx  DWORD KINX_PENDEVENTS\n", kd.KINX_PENDEVENTS);
    printf("0xFFFFCB44 : %08lx  DWORD KINX_KERNRESERVE\n", kd.KINX_KERNRESERVE);
    printf("0xFFFFCB48 : %08lx  DWORD KINX_API_MASK\n", kd.KINX_API_MASK);
    printf("0xFFFFCB4C : %08lx  DWORD KINX_NLS_CP\n", kd.KINX_NLS_CP);
    printf("0xFFFFCB50 : %08lx  DWORD KINX_NLS_SYSLOC\n", kd.KINX_NLS_SYSLOC);
    printf("0xFFFFCB54 : %08lx  DWORD KINX_NLS_USERLOC\n", kd.KINX_NLS_USERLOC);
    printf("0xFFFFCB58 : %08lx  DWORD KINX_HEAP_WASTE\n", kd.KINX_HEAP_WASTE);
    printf("0xFFFFCB5C : %08lx  DWORD KINX_DEBUGGER\n", kd.KINX_DEBUGGER);
    printf("0xFFFFCB60 : %08lx  APISETARRAYPTR KINX_APISETS\n", kd.KINX_APISETS);

    dumpapiptrs();

    printf("0xFFFFCB64 : %08lx  DWORD KINX_MINPAGEFREE\n", kd.KINX_MINPAGEFREE);
    printf("0xFFFFCB68 : %08lx  DWORD KINX_CELOGSTATUS\n", kd.KINX_CELOGSTATUS);
    printf("0xFFFFCB6C : %08lx  SECTIONPTR KINX_NKSECTION\n", kd.KINX_NKSECTION);
    printf("0xFFFFCB70 : %08lx  DWORD KINX_PTR_CURTOKEN\n", kd.KINX_PTR_CURTOKEN);
    printf("0xFFFFCB74 : %08lx  DWORD KINX_TIMECHANGECOUNT\n", kd.KINX_TIMECHANGECOUNT);
    printf("0xFFFFCB78 : %08lx  DWORD KINX_30\n", kd.KINX_30);
    printf("0xFFFFCB7C : %08lx  DWORD KINX_NKSIG\n", kd.KINX_NKSIG);
}

#define HANDLE_ADDRESS_MASK 0x1ffffffc
HDATAPTR cvHandle2HDataPtr(HANDLE h)
{
    return (HDATAPTR)kd.handleBase+((DWORD)h&HANDLE_ADDRESS_MASK);
}


bool ITGetHandles(const std::string& type, HANDLE hProc, HandleInfoVector& v, std::string& strbuf)
{
    GetHandlesParams *inbuf=NULL;
    DWORD insize= PTR_DIFF(inbuf, inbuf->type+type.size()+1);
    inbuf= (GetHandlesParams *)RapiAlloc(insize);

    DWORD outsize=0;
    GetHandlesResult *outbuf=NULL;

    inbuf->hProc= hProc;
    strncpy(inbuf->type, type.c_str(), 8);

    HRESULT res= ItsutilsInvoke("ITGetHandles",
            sizeof(GetHandlesParams), (BYTE*)inbuf,
            &outsize, (BYTE**)&outbuf);
    if (res || outbuf==NULL)
    {
        error(res, "ITGetHandles");
        return false;
    }
    v.resize(outbuf->count);
    memcpy(&v[0], outbuf->data, v.size()*sizeof(HandleInfo));
    strbuf= std::string((char*)(outbuf->data+outbuf->count), (char*)outbuf+outsize);

    RapiFree(outbuf);

    return true;
}
void DumpProxy(PROXY*p)
{
    debug("%08x %08x %08x %08x %08x  obj=%08x, t=%02x p=%02x, c=%02x, th=%08x, ret=%08x\n",

        p->pQPrev, p->pQNext, p->pQUp, p->pQDown, p->pThLinkNext,
        p->pObject, p->bType, p->prio, p->wCount, p->pTh, p->dwRetVal);

}
void DumpProxy(PROXYPTR addr)
{
    PROXY *prox;
    if (!ReadProxy(addr, &prox))
        return;
    DumpProxy(prox);
}

void DumpCallstack(CALLSTACK *cs)
{
    debug("n=%08x ret=%08x proc=%08x aky=%08x ex=%08x, sp=%08x info=%08x\n",
        cs->pcstkNext, cs->retAddr, cs->pprcLast, cs->akyLast, cs->extra, cs->dwPrevSP, cs->dwPrcInfo);
}
void DumpCallstackList(CALLSTACKPTR csp)
{
    while (csp) {
        CALLSTACK *cs;
        if (!ReadCallstack(csp, &cs))
            break;
        DumpCallstack(cs);
        csp= cs->pcstkNext;
    }
}
bool DumpThreadInfo(DWORD addr)
{
    THREAD *thd;
    if (!ReadThread(addr, &thd))
        return false;

    debug("sizeof(thread)= %d\n", sizeof(THREAD));

    debug("info=%04x, susp=%d, wait=%d, bprio=%02x, cprio=%02x, wcount=%04x\n",
            thd->wInfo, thd->bSuspendCnt, thd->bWaitState, thd->bBPrio, thd->bCPrio, thd->wCount);

    debug("tls=%08x s=%08x ns=%08x start=%08x curpc=%08x cursp=%08x\n",
            thd->tlsPtr, thd->tlsSecure, thd->tlsNonSecure,
            thd->dwStartAddr, thd->ctx.Pc, thd->ctx.Sp);

    if (thd->lpProxy) {
        debug("first proxy: ");
        DumpProxy(thd->lpProxy);
    }
    if (thd->lpCritProxy) {
        debug("crit proxy: ");
        DumpProxy(thd->lpCritProxy);
    }
    debug("proxies:\n");
    PROXYPTR p= thd->pProxList;
    while (p) {
        PROXY *prox;
        if (!ReadProxy(p, &prox))
            break;
        DumpProxy(prox);
        p= prox->pThLinkNext;
    }

    debug("callstack:\n");
    DumpCallstackList(thd->pcstkTop);
    debug("interrupt cstack:\n");
    DumpCallstack(&thd->IntrStk);
    DumpCallstackList(thd->IntrStk.pcstkNext);
    return true;
}
bool DumpProcessInfo(DWORD addr)
{
    PROCESS *proc;
    if (!ReadProcess(addr, &proc))
        return false;

    debug("sizeof(proc)= %d\n", sizeof(PROCESS));

    debug("id=%d dbg=%d chain=%d trust=%02x h=%08x vm=%08x aky=%08x basep=%08x\n",
            proc->procnum, proc->DbgActive, proc->bChainDebug, proc->bTrustLevel,
            proc->hProc, proc->dwVMBase, proc->aky, proc->BasePtr);
    debug("1stthread=%08x dbgthread=%08x mainthd=%08x zone=%08x\n",
            proc->pTh, proc->hDbgrThrd, proc->pMainTh, proc->ZonePtr);
    debug("rsc=%08x  dying=%d prio=%02x ndbg=%d tok=%08x\n", proc->pmodResource, proc->dwDyingThreads, proc->bPrio, proc->fNoDebug, proc->hTok);
    debug("tls: low=%08x high=%08x,  EHpfn=%08lx\n",
            proc->tlsLowUsed, proc->tlsHighUsed, proc->pfnEH);

    WSTR *procname;
    if (!ReadWString(proc->lpszProcName, &procname))
        return false;
    WSTR *cmdline;
    if (!ReadWString(proc->pcmdline, &cmdline))
        return false;
    debug("name: %s\n", ToString(procname->str).c_str());
    debug("cmdl: %s\n", ToString(cmdline->str).c_str());


    debug("proxies:\n");
    PROXYPTR p= proc->pProxList;
    while (p) {
        PROXY *prox;
        if (!ReadProxy(p, &prox))
            break;
        DumpProxy(prox);
        p= prox->pThLinkNext;
    }
    return true;
}
bool DumpMemoryBlock(DWORD addr, DWORD size)
{
    ByteVector data(size);
    DWORD nread;
    if (!ITReadProcessMemory(0, addr, &data[0], data.size(), &nread))
        return false;
    debug("%s\n", hexdump(0, &data[0], data.size(), 4).c_str());
    return true;
}
DWORD processAddress(DWORD vmbase, DWORD addr)
{
    if (addr&0xfe000000)
        return addr;
    return addr+vmbase;
}
bool DumpHeapBlock(DWORD vmbase, DWORD addr)
{
    addr= processAddress(vmbase, addr);
    DWORD size=ReadDword(addr-8);
    if (size>=0x1000)
        return false;
    return DumpMemoryBlock(addr, size);
}

bool DumpHandleInfo(HANDLE hHandle)
{
    HDATAPTR hdp = cvHandle2HDataPtr(hHandle);
    HDATA *hd;
    if (!ReadHData(hdp, &hd))
        return false;
    CINFO *ci;
    if (!ReadCInfo(hd->pci, &ci))
        return false;

    std::string htype= std::string(ci->acName, ci->acName+4);
    debug("%08lx %s: lock=%08lx ref=%08lx obj=%08lx info=%08lx\n",
            hdp, htype.c_str(), 
            hd->lock, hd->ref, hd->pvObj, hd->dwInfo);

    PROCESS *proc;
    if (!ReadProcess(ci->pServer, &proc))
        return false;
    WSTR *procname;
    if (!ReadWString(proc->lpszProcName, &procname))
        return false;
    WCHAR empty[1]= {0};
    debug("     d=%02x t=%02x api: n=%d, %08lx:%08lx  svr=%08lx (h=%08lx, n=%ls)\n",
            ci->disp, ci->type, ci->cMethods, ci->ppfnMethods, ci->pdwSig, 
            ci->pServer, proc->hProc, procname ? procname->str : empty);

//APIS:0x24  EVNT:A8  FMAP:40  MUTX:A8  SEMP:A8  PROC:f0, THRD:240
    if (htype=="THRD")
        DumpThreadInfo(hd->pvObj);
    else if (htype=="PROC")
        DumpProcessInfo(hd->pvObj);
    else if (htype=="APIS")
        DumpMemoryBlock(hd->pvObj, 0x24);
    else if (htype=="FMAP")
        DumpMemoryBlock(hd->pvObj, 0x40);
    else if (ci->pServer==0)
        DumpMemoryBlock(hd->pvObj, 0xa8);
    else if (hd->pvObj>0x10000)
        DumpHeapBlock(proc->dwVMBase,hd->pvObj);
    // else  socket id

    return true;
}
/*
-lsys
for (int i=0 ; i<32 ; i++)
    dump_handle(kd.ahSys[i]);

-lirqs
for (int i=0 ; i<32 ; i++) {
    printf("%08lx ", kd.alpvIntrData[i]);
    dump_handle(kd.alpeIntrEvents[i]);
}
-lprocs
dump_proc(kd.KINX_PROCARRAY);

-lhandles

find_handle_list
romhdr=kd.KINX_PTOC;
toc=romhdr+sizeof(ROMHDR);
for(int i=0 ; i<romhdr->nModules ; i++)
   if (_wcscmp(toc->szFileName, L"nk.exe")==0) {
      
      return find_data_seg(toc->o32_list, toc->e32_entry->n_obj);
   }
*/
void usage()
{
    printf("(C) 2003-2008 Willem jan Hengeveld  itsme@xs4all.nl\n");
    printf("Usage: phandle [options]\n");
    printf("    -t TYPE   : lists handles for type\n");
    printf("    -h HANDLE : lists info for specific handle\n");
    printf("    -p HANDLE | -n name : lists handles for specific process\n");
    printf("    -k        : dump kdata struct\n");
//todo    printf("    -a        : dump apis\n");
}
int main( int argc, char *argv[])
{
    std::string handletype;
    HANDLE hDumpHandle=INVALID_HANDLE_VALUE;
    std::string processFilter;
    HANDLE hProcessFilter=INVALID_HANDLE_VALUE;
    bool dump_kdata= false;
    DebugStdOut();
    for (int i=1 ; i<argc ; i++)
    {
        if (argv[i][0]=='-') switch(argv[i][1])
        {
            case 't': HANDLESTROPTION(handletype); break;
            case 'h': HANDLEULOPTION(hDumpHandle, HANDLE); break;
            case 'n': HANDLESTROPTION(processFilter); break;
            case 'p': HANDLEULOPTION(hProcessFilter, HANDLE); break;
            case 'k': dump_kdata= true; break;
            default: usage(); 
                     return 1;
        }
        else {
            usage();
            return 1;
        }
    }
/*
    debug("sizeof(CPUCONTEXT) = %04x\n", sizeof(CPUCONTEXT));
    debug("sizeof(WSTR) = %04x\n", sizeof(WSTR));
    debug("sizeof(openexe_t) = %04x\n", sizeof(openexe_t));
    debug("sizeof(info) = %04x\n", sizeof(info));
    debug("sizeof(e32_lite420) = %04x\n", sizeof(e32_lite420));
    debug("sizeof(e32_lite500) = %04x\n", sizeof(e32_lite500));
    debug("sizeof(o32_lite) = %04x\n", sizeof(o32_lite));
    debug("sizeof(CALLSTACK) = %04x\n", sizeof(CALLSTACK));
    debug("sizeof(PGPOOL_Q) = %04x\n", sizeof(PGPOOL_Q));
    debug("sizeof(THREAD500) = %04x\n", sizeof(THREAD500));
    debug("sizeof(PROCESS420) = %04x\n", sizeof(PROCESS420));
    debug("sizeof(PROCESS500) = %04x\n", sizeof(PROCESS500));
    debug("sizeof(CINFO) = %04x\n", sizeof(CINFO));
    debug("sizeof(HDATA) = %04x\n", sizeof(HDATA));
    debug("sizeof(KData) = %04x\n", sizeof(KData));
*/

    CheckITSDll();
    if (!ReadKData())
        return 1;

    if (dump_kdata)
        DumpKData();
    else if (hDumpHandle!=INVALID_HANDLE_VALUE)
        DumpHandleInfo(hDumpHandle);
    else {
        if (!processFilter.empty())
            hProcessFilter= ITGetProcessHandle(processFilter);

        HandleInfoVector v;
        std::string strbuf;
        if (ITGetHandles(handletype, hProcessFilter, v, strbuf)) {
            for (HandleInfoVector::iterator i=v.begin() ; i!=v.end() ; i++)
                printf("%08lx %s -> %08lx : %08lx %s\n", (*i).handle, (*i).type, (*i).hProc, (*i).pvObj, strbuf.substr((*i).descstart, (*i).descend-(*i).descstart).c_str());
        }
    }

    StopItsutils();

    return 0;
}



