#include "debug.h"
#include <Tlhelp32.h>

// c:/local/WINCE420/PUBLIC/COMMON/SDK/INC/kfuncs.h
//    SH_*  
// c:/local/WINCE420/PUBLIC/COMMON/OAK/INC/pkfuncs.h
//    KINX_*  
// c:/local/WINCE420/PRIVATE/WINCEOS/COREOS/NK/INC/kernel.h
//    CINFO, Process, Thread, HDATA, MemBlock, VA_BLOCK, FSMAP
//    APISET
// c:/local/WINCE420/PRIVATE/WINCEOS/COREOS/NK/INC/nkarm.h
//    CPUCONTEXT, KDataStruct, ArmHigh
// c:\local\WINCE420\PUBLIC\COMMON\OAK\INC\pehdr.h
//    e32_lite, o32_lite
// c:/local/WINCE420/PRIVATE/WINCEOS/COREOS/NK/INC/schedule.h
//    EVENT, MUTEX, SEMAPHORE

#include "cenk.h"
#include "cever_deps.h"
#include "kernelmisc.h"
/*
HDATA
    DList       linkage;    // 00: links for active handle list
        DList *fwd;             // 00: forward link
        DList *back;            // 04: backward link
    HANDLE      hValue;     // 08: Current value of handle (nonce)
    ACCESSLOCK  lock;       // 0C: access information
    REFINFO     ref;        // 10: reference information
        ulong   count;          // 10:
        FULLREF *pFr;           // 10: ptr to ushort  usRefs[MAX_PROCESSES];
    const CINFO *pci;       // 14: ptr to object class description structure
    PVOID       pvObj;      // 18: ptr to object (in server address space )
    DWORD       dwInfo;     // 1C: extra handle info

CINFO
    char        acName[4];  // 00: object type ID string
    uchar       disp;       // 04: type of dispatch
    uchar       type;       // 05: api handle type
    ushort      cMethods;   // 06: # of methods in dispatch table
    const PFNVOID *ppfnMethods;// 08: ptr to array of methods (in server address space)
    const DWORD *pdwSig;    // 0C: ptr to array of method signatures
    PPROCESS    pServer;    // 10: ptr to server process

 */
//--------------- SOCK_INFO is in wstype.h ----------------
// but it seems impossible to combine it with the kernel headers.
//#include "sockinfo.h"
#include "sockinfo420.h"

//#include "device420.h"			// fsopendev_t

#if _WIN32_WCE==300
#include "filehandle300.h"
#elif _WIN32_WCE==420
// this is only defined in the wce4.x sdk, not for 3.0
#include "filehandle300.h"
#elif _WIN32_WCE==500
#include "filehandle300.h"
#else
#error "unknown windows ce version"
#endif

#include <map>
#include <set>
#include <string>
#include "stringutils.h"

typedef std::set<const CINFO*> CInfoSet;
typedef std::map<std::string,CInfoSet> CInfoMap;

//HANDLE g_hFilesysProc;
//HANDLE g_hDeviceProc;

CInfoMap cinfomap;
DWORD *GetPagesList(MEMBLOCK *p)
{
    if (GetWinceVersion()<4)
        return (DWORD*)&(p->aPages);
    else
        return (DWORD*)p->aPages;
}
bool dumpmem(HANDLE hProc, DWORD dwOfs, DWORD dwLen, const std::string& msg)
{
    ByteVector dw; dw.resize(dwLen);
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)dwOfs, vectorptr(dw), dw.size(), &nRead)) {
        error("dumpmem(%08lx, %08lx)", hProc, dwOfs);
        return false;
    }
    bighexdump(dwOfs, dw, hexdumpflags(DUMPUNIT_DWORD, 4, DUMP_HEX)|HEXDUMP_WITH_OFFSET);

    return true;
}

HANDLE GetProcessHandle(WCHAR *wszProcessName)
{
    HANDLE hTH= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS|TH32CS_SNAPNOHEAPS, 0);

    PROCESSENTRY32 pe;
    pe.dwSize= sizeof(PROCESSENTRY32);

    HANDLE hProc= INVALID_HANDLE_VALUE;
    if (Process32First(hTH, &pe))
    {
        do {

            if (wcsicmp(wszProcessName, pe.szExeFile)==0)
            {
                hProc= OpenProcess(0, 0, pe.th32ProcessID);
                if (hProc != INVALID_HANDLE_VALUE && hProc!=NULL)
                    break;
            }
        } while (Process32Next(hTH, &pe));
    }

    CloseToolhelp32Snapshot(hTH);

    return hProc;
}
char *GetCInfoName(const CINFO *ci)
{
    if (!isValidPtr((DWORD)ci)) {
        debug("GetCInfoName: INVALID PTR %08lx\n", ci);
        return "----";
    }
	static char name[5];

    for (int i=0 ; i<4 ; i++)
        name[i]= ci->acName[i];
    name[4]=0;
    return name;
}
void DumpCInfo(const CINFO *pci);
void RegisterCInfo(const CINFO *pci, int apiindex)
{
    std::string name(GetCInfoName(pci));

    if (apiindex>=0)
        debug("apiset %02x: %hs\n", apiindex, name.c_str());

	cinfomap[name].insert(pci);
}


void DumpCInfoMap()
{
	for (CInfoMap::iterator mi= cinfomap.begin() ; mi!=cinfomap.end() ; ++mi)
	{
		debug("....%hs....\n", (*mi).first.c_str());
		for (CInfoSet::iterator si= (*mi).second.begin() ; si!=(*mi).second.end() ; ++si)
		{
			DumpCInfo(*si);
		}
	}
}
char *GetMethodSigString(DWORD dwSig)
{
	static char str[256];
	char *p= str;

	p+=sprintf(p, "(");
	for (int i=0 ; i<16 && dwSig ; i++)
	{
		if (i)	p+=sprintf(p, ", ");
		switch(dwSig&3)
		{
		case 0: p+=sprintf(p, "DWORD"); break;
		case 1: p+=sprintf(p, "PTR"); break;
		case 2: p+=sprintf(p, "I64"); break;
		case 3: p+=sprintf(p, "???"); break;
		}
		dwSig>>=2;
	}
	p+=sprintf(p, ")");
	return str;
}

void DumpCInfo(const CINFO *pci)
{
    if (!isValidPtr((DWORD)pci)) {
        debug("DumpCInfo: INVALID PTR %08lx\n", pci);
        return;
    }
	debug("CINFO %08lx  %-4s  n=%d disp=%02x type=%02x  methods=%08lx sigs=%08lx server=%08lx %ls\n", 
		pci, GetCInfoName(pci), pci->cMethods, pci->disp, pci->type,
		pci->ppfnMethods, pci->pdwSig,
		pci->pServer, IsBadReadPtr(pci->pServer, sizeof(PROCESS))?L"-":pci->pServer->lpszProcName);

	const PFNVOID *ppfnMethods= IsBadReadPtr(pci->pServer, sizeof(PROCESS))
			?pci->ppfnMethods
			:(const PFNVOID *)MapPtrUnsecure((void*)pci->ppfnMethods, pci->pServer->hProc);
	const DWORD *pdwSig= IsBadReadPtr(pci->pServer, sizeof(PROCESS))
			?pci->pdwSig
			:(const DWORD *)MapPtrUnsecure((void*)pci->pdwSig, pci->pServer->hProc);
	for (int i=0 ; i<pci->cMethods ; i++)
	{
		debug("apiset  %-4s %3d %08lx %hs\n", GetCInfoName(pci), 
			i, ppfnMethods[i], (pdwSig==NULL || IsBadReadPtr(pdwSig, sizeof(DWORD)*i))?"-":GetMethodSigString(pdwSig[i]));
	}
}
void DumpThreadTimes(HANDLE hThread)
{
	FILETIME tCreate, tExit, tKernel, tUser;
    if (!GetThreadTimes(hThread, &tCreate, &tExit, &tKernel, &tUser))
	{
		error("GetThreadTimes");
        return;
	}

	debug("      cr= %08lx%08lx  ex=%08lx%08lx  k=%08lx%08lx  u=%08lx%08lx\n",
		tCreate.dwHighDateTime, tCreate.dwLowDateTime,
		tExit.dwHighDateTime, tExit.dwLowDateTime,
		tKernel.dwHighDateTime, tKernel.dwLowDateTime,
		tUser.dwHighDateTime, tUser.dwLowDateTime);
}

void DumpHeapEntry(HEAPENTRY32 *he)
{
    if (!isValidPtr((DWORD)he)) {
        debug("DumpHeapEntry: INVALID PTR %08lx\n", he);
        return;
    }
	debug("    %4d hBlk=%08lx addr=%08lx size=%08lx fl=%08lx lck=%d ?=%08lx pid=%08lx hid=%08lx\n",
		he->dwSize, he->hHandle, he->dwAddress, he->dwBlockSize,
		he->dwFlags, he->dwLockCount, he->dwResvd, 
		he->th32ProcessID, he->th32HeapID); 

}

void DumpHeap(HANDLE hTH, DWORD nProcessId, DWORD nHeapId)
{
	HEAPENTRY32 he;
	

	DWORD dwTotal=0;

	__try {
		he.dwSize= sizeof(HEAPENTRY32);
		if (Heap32First(hTH, &he, nProcessId, nHeapId))
		{
			do {
				//DumpHeapEntry(&he);

				dwTotal += he.dwBlockSize;

				he.dwSize= sizeof(HEAPENTRY32);
			} while (Heap32Next(hTH, &he));
		}
	}
	__except(1) {
		debug("exception reading heap\n");
	}

	error("done looping over heap - structsize=%d  heapsize=%ld", sizeof(HEAPENTRY32), dwTotal);
}


void DumpHeapListEntry(HEAPLIST32 *le)
{
    if (!isValidPtr((DWORD)le)) {
        debug("DumpHeapListEntry: INVALID PTR %08lx\n", le);
        return;
    }
	debug("%4d pid=%08lx hid=%08lx fl=%08lx\n", 
		le->dwSize, le->th32ProcessID, le->th32HeapID, le->dwFlags);
}

void DumpHeapLists(HANDLE hTH)
{
	HEAPLIST32 le;
	le.dwSize= sizeof(HEAPLIST32);

	if (Heap32ListFirst(hTH, &le))
	{
		do {
			DumpHeapListEntry(&le);

			DumpHeap(hTH, le.th32ProcessID, le.th32HeapID);
			le.dwSize= sizeof(HEAPLIST32);
		} while (Heap32ListNext(hTH, &le));
	}

	error("done looping over heap lists - structsize=%d", sizeof(HEAPLIST32));
}

void DumpModuleEntry(MODULEENTRY32 *me)
{
    if (!isValidPtr((DWORD)me)) {
        debug("DumpModuleEntry: INVALID PTR %08lx\n", me);
        return;
    }
	debug("%4d fl=%08lx mid=%08lx pid=%08lx gusg=%3d pusg=%08lx base=%08lx size=%08lx hmod=%08lx mod=%ls exe=%ls\n",
		me->dwSize, me->dwFlags, me->th32ModuleID, me->th32ProcessID, 
		me->GlblcntUsage, me->ProccntUsage, 
		me->modBaseAddr, me->modBaseSize, 
		me->hModule, 
		me->szModule, me->szExePath);

}

void DumpModules(HANDLE hTH)
{
	MODULEENTRY32 me;
	me.dwSize= sizeof(MODULEENTRY32);

	if (Module32First(hTH, &me))
	{
		do {
			DumpModuleEntry(&me);

			me.dwSize= sizeof(MODULEENTRY32);
		} while (Module32Next(hTH, &me));
	}

	error("done looping over modules - structsize=%d", sizeof(MODULEENTRY32));
}

void DumpProcessEntry(PROCESSENTRY32 *pe)
{
    if (!isValidPtr((DWORD)pe)) {
        debug("DumpProcessEntry: INVALID PTR %08lx\n", pe);
        return;
    }
	debug("%2d usg=%d pid=%08lx hid=%08lx mid=%08lx #t=%2d ppid=%08lx pri=%08lx fl=%08lx mem=%08lx acc=%08lx %ls\n",
		pe->dwSize, pe->cntUsage, pe->th32ProcessID, pe->th32DefaultHeapID, 
		pe->th32ModuleID, pe->cntThreads, pe->th32ParentProcessID, 
		pe->pcPriClassBase, pe->dwFlags, 

		pe->th32MemoryBase,	pe->th32AccessKey,
		pe->szExeFile); 
}

void DumpProcesses(HANDLE hTH)
{
	PROCESSENTRY32 pe;
	pe.dwSize= sizeof(PROCESSENTRY32);

	if (Process32First(hTH, &pe))
	{
		do {
			DumpProcessEntry(&pe);

			if (pe.th32DefaultHeapID)
				DumpHeap(hTH, pe.th32ProcessID, pe.th32DefaultHeapID);

			pe.dwSize= sizeof(PROCESSENTRY32);
		} while (Process32Next(hTH, &pe));
	}

	error("done looping over processes - structsize=%d", sizeof(PROCESSENTRY32));
}

void DumpThreadEntry(THREADENTRY32 *te)
{
    if (!isValidPtr((DWORD)te)) {
        debug("DumpThreadEntry: INVALID PTR %08lx\n", te);
        return;
    }
	debug("%2d usg=%d tid=%08lx opid=%08lx pri=%3d dpri=%3d fl=%08lx acc=%08lx cpid=%08lx\n",
		te->dwSize, te->cntUsage, te->th32ThreadID, te->th32OwnerProcessID, 
		te->tpBasePri, te->tpDeltaPri, te->dwFlags,te->th32AccessKey,
		te->th32CurrentProcessID);
}
void DumpThreads(HANDLE hTH)
{
	THREADENTRY32 te;
	te.dwSize= sizeof(THREADENTRY32);

	if (Thread32First(hTH, &te))
	{
		do {
			DumpThreadEntry(&te);

			DumpThreadTimes((HANDLE)te.th32ThreadID);

			te.dwSize= sizeof(THREADENTRY32);
		} while (Thread32Next(hTH, &te));
	}

	error("done looping over threads - structsize=%d", sizeof(THREADENTRY32));
}

void testtoolhelp()
{
	HANDLE hTH= CreateToolhelp32Snapshot(TH32CS_SNAPALL | TH32CS_GETALLMODS, 0);


	debug("-------------threads-------------\n");
	DumpThreads(hTH);

	debug("-------------process-------------\n");
	DumpProcesses(hTH);

	debug("-------------modules-------------\n");
	DumpModules(hTH);

	debug("-------------heaplists-------------\n");
	DumpHeapLists(hTH);

	CloseToolhelp32Snapshot(hTH);

}

DWORD SetAccess(HANDLE hProc, DWORD aky)
{
	//HANDLE hProc= (HANDLE)GetCurrentProcessId();

	HDATA *pHandle= cvHandle2HDataPtr(hProc);

	PROCESS *proc= (PROCESS*)pHandle->pvObj;

	DWORD oldaky= proc->aky;
	proc->aky= 0xffffffff;
	return oldaky;
}

DWORD GetHandleObject(HANDLE h)
{
	HDATA *hi= cvHandle2HDataPtr(h);
	return (DWORD)hi->pvObj;
}

TCHAR *GetProcessNameByHandle(HANDLE h)
{
	return ((PROCESS*)GetHandleObject(h))->lpszProcName;
}
// !!! os dependent
void DumpProcess(HANDLE hProc, PROCESS *p)
{
	debug("  num=%d vmbase=%08lx aky=%08lx base=%08lx e32.base=%08lx  %ls %ls", 
		p->procnum, p->dwVMBase, p->aky, p->BasePtr,
		p->e32.e32_vbase, p->lpszProcName, p->pcmdline);
/*
	if (p->o32_ptr)
	{
		for (int i=0 ; i<p->e32.e32_objcnt ; i++)
			debug("    o32-%d : data=%08lx real=%08lx\n", p->o32_ptr[i].o32_dataptr, p->o32_ptr[i].o32_realaddr);
	}
*/
}

// !!! os dependent
void DumpThread(HANDLE hProc, THREAD *t)
{
    if (!isValidPtr((DWORD)t)) {
        debug("DumpThread: INVALID PTR %08lx\n", t);
        return;
    }
	debug("  utime=%08lx ktime=%08lx proc=%08lx %ls",
		t->dwUserTime, t->dwKernTime, t->pOwnerProc, t->pOwnerProc->lpszProcName);
}

void DumpEvent(HANDLE hProc, EVENT *e)
{
    if (!isValidPtr((DWORD)e)) {
        debug("DumpEvent: INVALID PTR %08lx\n", e);
        return;
    }
	if (e->name)
		debug(" %ls", e->name->name);
}
void DumpApiSet(HANDLE hProc, APISET *a)
{
    if (!isValidPtr((DWORD)a)) {
        debug("DumpApiSet: INVALID PTR %08lx\n", a);
        return;
    }
	debug("  reg=%2d  %-4s  n=%d disp=%02x type=%02x  methods=%08lx sigs=%08lx server=%08lx %ls", 
            a->iReg, 
		GetCInfoName(&a->cinfo), a->cinfo.cMethods, a->cinfo.disp, a->cinfo.type,
		a->cinfo.ppfnMethods, a->cinfo.pdwSig,
		a->cinfo.pServer, a->cinfo.pServer->lpszProcName);

	RegisterCInfo(&a->cinfo, -1);
}
void DumpMutex(HANDLE hProc, MUTEX* m)
{
    if (!isValidPtr((DWORD)m)) {
        debug("DumpMutex: INVALID PTR %08lx\n", m);
        return;
    }
	debug(" %d locks", m->LockCount);
	if (m->name)
		debug(" %ls", m->name->name);
}
void DumpSemaphore(HANDLE hProc, SEMAPHORE* s)
{
    if (!isValidPtr((DWORD)s)) {
        debug("DumpSemaphore: INVALID PTR %08lx\n", s);
        return;
    }
	debug(" cur=%d max=%d pend=%d", s->lCount, s->lMaxCount, s->lPending);	
	if (s->name)
		debug(" %ls", s->name->name);
}
void DumpFSMap(HANDLE hProc, FSMAP* f)
{
    if (!isValidPtr((DWORD)f)) {
        debug("DumpFSMap: INVALID PTR %08lx\n", f);
        return;
    }
	if (f->name)
		debug(" %ls", f->name->name);
}
std::string dwptrvaluestr(HANDLE hProc, DWORD dwOfs)
{
    DWORD value;
    DWORD nRead;
    if (dwOfs==NULL) return "(null)";

    if (!ReadProcessMemory(hProc,  (void*)dwOfs, &value, sizeof(value), &nRead)) {
        error("dwptrvaluestr(%08lx,%08lx)", hProc, dwOfs);
        return "??";
    }
    return stringformat("%08lx", value);
}
std::string procstring(HANDLE hProc, DWORD dwOfs)
{
    WCHAR str[260];
    DWORD nRead;
    if (dwOfs==NULL) return "(null)";

    if (!ReadProcessMemory(hProc,  (void*)dwOfs, str, sizeof(str), &nRead)) {
        error("procstring(%08lx, %08lx)", hProc, dwOfs);
        return "??";
    }
    return ToString(str);
}
bool DumpHFSD(HANDLE hProc, void *p)
{
    // 48 byte struct.
    struct filedesc {
        DWORD next;      /* point to filedesc */
        DWORD prev;      /* point to filedesc */
        DWORD pPartition;      /* point to filedesc */
        DWORD dw2;
        DWORD pfileinfo;  /* point to fileinfo */
        DWORD dw3;
        DWORD hFile;
        DWORD pgtgtinfo;
        DWORD dw4[4];
    } fd;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)p, &fd, sizeof(fd), &nRead)) {
        error("DumpHFSD(%08lx, %08lx) - reading filedesc", hProc, p);
        return false;
    }
    debug(" fileinfo: part=%08lx  n=%d", fd.pPartition, fd.dw2);

    struct gtgtinfo {
        DWORD magic;
        DWORD pdgdginfo;
        DWORD dw2;
        DWORD pwstrName;
        DWORD pNext;
        DWORD pPrev;
        DWORD dw6;
        DWORD dw7;
    } gtgt;
    if (!ReadProcessMemory(hProc,  (void*)fd.pgtgtinfo, &gtgt, sizeof(gtgt), &nRead)) {
        error("DumpHFSD(%08lx, %08lx) - reading gtgtinfo", hProc, fd.pgtgtinfo);
        return false;
    }
    debug(" gtgt(%08lx): n=%08lx p=%08lx  dgdg=%08lx  %hs", fd.pgtgtinfo, gtgt.pNext, gtgt.pPrev, gtgt.pdgdginfo,
            procstring(hProc, gtgt.pwstrName).c_str());

    return true;
}
// wm2005:
// STRG
//   magic
//   pVolume
//   pPartition
//   w4
//   w5
//   pnext
//   w7
//   w8
// STRG+32
//   next
//   prev
bool DumpSTRG(HANDLE hProc, void *p)
{
    DWORD nRead;
    struct storagedesc {
        DWORD magic;        // 0x00596164 -> store handle,  0x64615900 -> partition handle
        DWORD pstorageinfo;
        DWORD ppartitioninfo;
        DWORD dw1[5];
        DWORD pdw1[2];
    } sd;
    if (!ReadProcessMemory(hProc,  (void*)p, &sd, sizeof(sd), &nRead)) {
        error("DumpSTRG(%08lx, %08lx) - reading storagedesc", hProc, p);
        return false;
    }
    struct storageinfo {
        DWORD dw1[3];       // dw1[4]  in wm2005
        WCHAR devname[16];
        WCHAR desc1[32];
        WCHAR desc2[32];
        WCHAR partdll[260];
        WCHAR profilekey[260];
        WCHAR fsname[260];
        DWORD dw2[165];
        WCHAR desc3[32];
        DWORD dw3[29];
        WCHAR driverkey[260];
        DWORD dw4[11];
    } si;
    if (!ReadProcessMemory(hProc,  (void*)sd.pstorageinfo, &si, sizeof(si), &nRead)) {
        error("DumpSTRG(%08lx, %08lx) - reading storageinfo", hProc, sd.pstorageinfo);
        return false;
    }
    debug(" storagedev %ls %ls %ls", si.devname, si.desc1, si.desc2);

    return true;
}
bool DumpFFSD(HANDLE hProc, void *p)
{
    // 48 byte struct.
    struct filedesc {
        DWORD next;
        DWORD prev;
        DWORD pPartition;
        DWORD dw2;
        DWORD pfilenameinfo;
        DWORD hProcess;
        DWORD hFile;
        DWORD pgtgtinfo;
        DWORD dw4[4];
    } fd;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)p, &fd, sizeof(fd), &nRead)) {
        error("DumpFFSD(%08lx, %08lx) - reading filedesc", hProc, p);
        return false;
    }
    debug(" fileinfo: part=%08lx  n=%d", fd.pPartition, fd.dw2);
    struct filenameinfo {
        DWORD pfilename;
        DWORD pPartition;
        DWORD dw[6];
    } fi;
    if (!ReadProcessMemory(hProc,  (void*)fd.pfilenameinfo, &fi, sizeof(fi), &nRead)) {
        error("reading filesys.exe : %08lx\n", fd.pfilenameinfo);
        return false;
    }

    struct filename {
        DWORD dw;
        WCHAR name[260];
    } fn;
    if (!ReadProcessMemory(hProc,  (void*)fi.pfilename, &fn, sizeof(fn), &nRead)) {
        error("reading filesys.exe : %08lx\n", fi.pfilename);
        return false;
    }
    debug(" %08lx  %ls", fn.dw, fn.name);

    return true;
}
bool DumpPartitionv5(HANDLE hProc, void *p)
{
    struct partitioninfo {
        DWORD dw1[8];               // 0x0000
        WCHAR volumename[32];       // 0x00bc
        WCHAR partitionname[32];    // 0x00fc
        DWORD dw2[5];               // 0x013c
        WCHAR fstype[12];           // 0x0150
    } pi;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)p, &pi, sizeof(pi), &nRead)) {
        error("DumpPart(%08lx, %08lx) - reading partitioninfo", hProc, p);
        return false;
    }
    debug(" partition: %ls %ls/%ls", pi.fstype, pi.volumename, pi.partitionname);
    return true;
}

bool DumpPartition(HANDLE hProc, void *p)
{
    // todo: in wm2005 this is different
    struct partitioninfo {
        DWORD dw1[8];
        WCHAR name[66];
        DWORD dw2[2];
    } pi;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)p, &pi, sizeof(pi), &nRead)) {
        error("DumpPart(%08lx, %08lx) - reading partitioninfo", hProc, p);
        return false;
    }
    debug(" partition: %ls", pi.name);
    return true;
}
bool DumpBlockDevice(HANDLE hProc, void *p)
{
    struct blockdev {
        DWORD dw1[11];
        WCHAR name1[256];
        DWORD dw2[13];
        WCHAR name2[28];
        DWORD dw3[2];
    } bdev;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)p, &bdev, sizeof(bdev), &nRead)) {
        error("DumpBlockDev(%08lx, %08lx) - reading blockdev", hProc, p);
        return false;
    }
    debug(" blockdev: %ls  %ls", bdev.name1, bdev.name2);
    return true;
}
bool DumpW32Device(HANDLE hProc, fsopendev_t *d)
{
    // W32D
    //   struct fsopendev_t *nextptr;	// next one in linked list
    //   DWORD dwOpenData;
    //   fsdev_t *lpDev;
    //   DWORD *lpdwDevRefCnt;	// since we set lpDev to NULL on device deregister
    //   DWORD dwOpenRefCnt;     // ref count for this structure 
    //   HANDLE KHandle;			// kernel handle pointing to this structure
    //   HPROCESS hProc;			// process owning this handle
    fsopendev_t odev;
    DWORD nRead;
	// W32D struct is 0x28 bytes
	// this handle can only be read from the context of device.exe
    if (!ReadProcessMemory(hProc,  (void*)d, &odev, sizeof(odev), &nRead)) {
        error("DumpW32Dev(%08lx, %08lx) - reading fsopendev_t", hProc, d);
        return false;
    }
    debug(" opendev next=%08lx data=%08lx dev=%08lx devref=%08lx->(%s) openref=%08lx  h=%08lx hproc=%08lx",
            odev.nextptr, odev.dwOpenData, odev.lpDev, 
            odev.lpdwDevRefCnt, dwptrvaluestr(hProc, (DWORD)odev.lpdwDevRefCnt).c_str(), 
            odev.dwOpenRefCnt, odev.KHandle, odev.hProc);

// new: c:\local\WINCE500\PRIVATE\WINCEOS\COREOS\DEVICE\INC\devmgrp.h
// old: c:\local\WINCE500\PRIVATE\SERVERS\SERVICES\LIB\serv.h
    fsdev_t dev;
    if (!ReadProcessMemory(hProc,  (void*)odev.lpDev, &dev, sizeof(dev), &nRead)) {
        error("DumpW32Dev(%08lx, %08lx) - reading fsdev_t", hProc, odev.lpDev);
        return false;
    }
    debug("   %c%c%c%d:", dev.type[0], dev.type[1], dev.type[2], dev.index);
    return true;
}

std::string FindNameForOid(CEOID oid);
bool GetNameForOid(CEOID oid, std::string& name)
{
    CEOIDINFO info;
    if (!CeOidGetInfo(oid, &info))
    {
        return false;
    }
    switch(info.wObjType)
    {
        case OBJTYPE_INVALID: name="invalid objectid"; break;
        case OBJTYPE_FILE: name=stringformat("file: %ls", info.infFile.szFileName); break;
        case OBJTYPE_DIRECTORY: name=stringformat("dir: %ls", info.infDirectory.szDirName); break;
        case OBJTYPE_DATABASE: name=stringformat("db: %ls", info.infDatabase.szDbaseName); break;
        case OBJTYPE_RECORD: name=stringformat("rec from %hs", FindNameForOid(info.infRecord.oidParent).c_str()); break;
        default: name=stringformat("unknown objtype %d", info.wObjType); 
    }
    return true;
}
std::string FindNameForOid(CEOID oid)
{
    oid &= 0xffffff;
    std::string name;
    for (int i=0 ; i<768 ; i++)
    {
        //  upto 768, since CeOidGetInfo crashes when called with oid's over 0xe0000000
        if (GetNameForOid(oid | i<<22, name))
            return name;
    }

    return "not found";
}

bool DumpW32File(HANDLE hProc, FHANDLE *f)
{
    struct {
        DWORD d[6];
    } fh;
    DWORD nRead;
	// W32H struct is 0x18 bytes
	// this handle can only be read from the context of filesys.exe
    if (!ReadProcessMemory(hProc,  (void*)f, &fh, sizeof(fh), &nRead)) {
        error("DumpW32File(%08lx, %08lx) - reading fn", hProc, f);
        return false;
    }
    debug(" %hs", hexdump((BYTE*)&fh, sizeof(fh)/sizeof(DWORD), 4).c_str());
    debug("  %hs", FindNameForOid(fh.d[3]).c_str());

    return true;
}

#define DBHANDLE void
bool DumpDatabase(HANDLE hProc, DBHANDLE *d)
{
    struct {
        DWORD d[18];
        // d[5] : oid
        // d[4] : volume struct
    } dbh;
    DWORD nRead;
	// DBOA struct is 0x48 bytes
	// this handle can only be read from the context of filesys.exe
    if (!ReadProcessMemory(hProc,  (void*)d, &dbh, sizeof(dbh), &nRead)) {
        error("DumpDatabase(%08lx, %08lx) - reading fn", hProc, d);
        return false;
    }
    debug(" %hs", hexdump((BYTE*)&dbh, sizeof(dbh)/sizeof(DWORD), 4).c_str());
    debug("  %hs", FindNameForOid(dbh.d[5]).c_str());
    return true;
}
bool DumpSocket(HANDLE hProc, DWORD s)
{
	// Sock struct is ? bytes
	// this handle can only be read from the context of device.exe
    struct socketdesc {
        DWORD dw1[10];
        DWORD pnext;
        DWORD dw2[2];
        DWORD ptr1;
        DWORD pproto;
        DWORD dw3[44];
        DWORD ptr2;
        DWORD dw4[1];
        DWORD ptr3;
        DWORD ptr4;
        DWORD dw5[1];
        DWORD ptr5;
        DWORD dw6[1];
        DWORD ptr6;
        DWORD ptr7;
        DWORD dw7[6];
        DWORD ptr8;
        DWORD dw8[5];
        DWORD ptr9;
        DWORD ptr10;
        DWORD ptr11;
        DWORD dw9[2];
        DWORD ptr12;
        DWORD ptr13;
        DWORD ptr14;
        DWORD dw10[43];
        DWORD ptr15;
    } sd;
    DWORD nRead;
    if (!ReadProcessMemory(hProc,  (void*)s, &sd, sizeof(sd), &nRead)) {
        error("DumpSocket(%08lx, %08lx) - reading sd", hProc, s);
        return false;
    }
    struct socketproto {
        DWORD dw1[7];
        WCHAR name[20];
        DWORD dw2[4];
    } sp;
    if (!ReadProcessMemory(hProc,  (void*)sd.pproto, &sp, sizeof(sp), &nRead)) {
        error("DumpSocket(%08lx, %08lx) - reading sp", hProc, sd.pproto);
        return false;
    }
    debug(" sock: next=%08lx proto=%ls", sd.pnext, sp.name);
/*
    dumpmem(hProc, sd.ptr1,  0x40, "socketmem ptr1");
    dumpmem(hProc, sd.ptr2,  0x40, "socketmem ptr2");
    dumpmem(hProc, sd.ptr3,  0x40, "socketmem ptr3");
    dumpmem(hProc, sd.ptr4,  0x40, "socketmem ptr4");
    dumpmem(hProc, sd.ptr5,  0x40, "socketmem ptr5");
    dumpmem(hProc, sd.ptr6,  0x40, "socketmem ptr6");
    dumpmem(hProc, sd.ptr7,  0x40, "socketmem ptr7");
    dumpmem(hProc, sd.ptr8,  0x40, "socketmem ptr8");
    dumpmem(hProc, sd.ptr9,  0x40, "socketmem ptr9");
    dumpmem(hProc, sd.ptr10, 0x40, "socketmem ptr10");
    dumpmem(hProc, sd.ptr11, 0x40, "socketmem ptr11");
    dumpmem(hProc, sd.ptr12, 0x40, "socketmem ptr12");
    dumpmem(hProc, sd.ptr13, 0x40, "socketmem ptr13");
    dumpmem(hProc, sd.ptr14, 0x40, "socketmem ptr14");
    dumpmem(hProc, sd.ptr15, 0x40, "socketmem ptr15");
*/
    return true;

}
bool isStartPtr(HDATA *ha) {
    if (!isValidPtr((DWORD)ha)) {
        debug("isStartPtr: ha INVALID PTR %08lx\n", ha);
        return true;
    }
    if (!isValidPtr((DWORD)ha->pci)) {
        debug("isStartPtr: ha->pci INVALID PTR %08lx\n", ha->pci);
        return true;
    }
    return ((((DWORD)ha->hValue)&3)!=2);
}
/*
 *   ha+00    8d94551c linkage.fwd
 *   ha+04    8dddfdd4 linkage.back
 *   ha+08    8d945542 hValue
 *   ha+0c    00040000 lock
 *   ha+10    0000     ref.pFr
 *   ha+12    0001     ref.count
 *   ha+14    8df5ba78 pci
 *     pci+00    6b636f53  acName[4];
 *     pci+04    04        disp;     
 *     pci+05    0b        type;     
 *     pci+06    000f      cMethods; 
 *     pci+08    01c910d8  ppfnMethods
 *     pci+0c    01c91118  pdwSig
 *     pci+10    8c0c3840  pServer
 *   ha+18    00361868 pvObj
 *   ha+1c    00000000 dwInfo
 */
void testhandle(HANDLE h)
{
	HDATA *hi= cvHandle2HDataPtr(h);

	HDATA *ha;

    bool bForward= true;
	ha=hi;
	do {
        if (!isValidPtr((DWORD)ha)) {
            if (bForward) {
                ha= (HDATA*)hi->linkage.back;
                bForward= false;
                if (!isValidPtr((DWORD)ha)) 
                    break;
            }
            else
                break;
        }
        if (isStartPtr(ha))
        {
            debug("Start of Handle list: %08lx\n", ha);
            ha= (HDATA*)(bForward ? ha->linkage.fwd : ha->linkage.back);
            continue;
        }
		debug("%08lx %-4s  %08lx %08lx", ha, GetCInfoName(ha->pci), ha->hValue, ha->pvObj);

		RegisterCInfo(ha->pci, -1);

        
        HANDLE hProc= (isValidPtr((DWORD)ha->pci) && isValidPtr((DWORD)ha->pci->pServer))? ha->pci->pServer->hProc : NULL;

		if (ha->pvObj && strncmp(ha->pci->acName, "PROC", 4)==0)
			DumpProcess(hProc, (PROCESS*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "THRD", 4)==0)
			DumpThread(hProc, (THREAD*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "APIS", 4)==0)
			DumpApiSet(hProc, (APISET*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "EVNT", 4)==0)
			DumpEvent(hProc, (EVENT*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "MUTX", 4)==0)
			DumpMutex(hProc, (MUTEX*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "SEMP", 4)==0)
			DumpSemaphore(hProc, (SEMAPHORE*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "FMAP", 4)==0)
			DumpFSMap(hProc, (FSMAP*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "W32D", 4)==0)
			DumpW32Device(hProc, (fsopendev_t*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "W32H", 4)==0)
			DumpW32File(hProc, (FHANDLE*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "DBOA", 4)==0)
			DumpDatabase(hProc, (DBHANDLE*)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "Sock", 4)==0)
			DumpSocket(hProc, (DWORD)ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "BDEV", 4)==0)
			DumpBlockDevice(hProc, ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "PFSD", 4)==0) {
//          if (wm2005())
//              DumpPartitionv5(hProc, ha->pvObj);
//          else
                DumpPartition(hProc, ha->pvObj);
        }
		else if (ha->pvObj && strncmp(ha->pci->acName, "HFSD", 4)==0)
			DumpHFSD(hProc, ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "FFSD", 4)==0)
			DumpFFSD(hProc, ha->pvObj);
		else if (ha->pvObj && strncmp(ha->pci->acName, "STRG", 4)==0)
			DumpSTRG(hProc, ha->pvObj);
		//PFAT              { +0x2c : char[11],   (void*)+0x00 : +0x38 : long, wchar[?] }
		//PRdr - device.exe { +0x10 : wchar[12] }
        //
        //wm2005 handles:
        //DMFS - device.exe
        //EDBO - filesys.exe { ?, 0x12345678, ... } l=0x40
        //FNOT - filesys.exe
        //PRdr - device.exe
        //ROM3 - filesys.exe
        //W32S - services.exe

        debug("\n");
        ha= (HDATA*)(bForward ? ha->linkage.fwd : ha->linkage.back);
	} while (ha!=hi && ha!=NULL);
	debug("\n");
}
std::string stringofmemblock(MEMBLOCK *p)
{
    if (p==NULL_BLOCK)
        return "NULL_BLOCK";
    else if (p==RESERVED_BLOCK)
        return "RESERVED_BLOCK";
    else {
        return stringformat("%08lx: key=%08lx us=%d fl=%02x ix=%04x pf=%04x lk=%d %08lx: %hs",
            p, p->alk, p->cUses, p->flags, ((DWORD)p->ixBase)&0xffff, ((DWORD)p->hPf)&0xffff, p->cLocks, GetPagesList(p),
            hexdump((BYTE*)(GetPagesList(p)), 16, 4).c_str());
    }
}
void DumpMemoryBlock(DWORD dwMemBlockOfs, MEMBLOCK *m)
{
    if (m)
        debug("MemBlock_%08lx: %hs\n", dwMemBlockOfs, stringofmemblock(m).c_str());
}
void DumpSection(DWORD dwSectionOfs, SECTION *s)
{
	debug("Section_%08x: %08lx: %hs\n", dwSectionOfs, s, hexdump((BYTE*)s, 16, 4).c_str());
	for (int j=0 ; j<0x200 ; j++)
	{
		DumpMemoryBlock(dwSectionOfs|(j<<VA_BLOCK), (*s)[j]);
	}
}

void SummarizeTLB2(DWORD dwVirtbase, DWORD dwTlbPhysAddr, DWORD pagesize, int nentries)
{
    DWORD *ptbl= (DWORD*)PhysToVirtUC(dwTlbPhysAddr);
    if (ptbl==NULL) {
        debug("ERROR: could not find virtual address for phys %08lx\n", dwTlbPhysAddr);
        return;
    }

    bool bStarted= false;
    DWORD dwStartVirt= 0;
    DWORD dwStartPhys= 0;
    DWORD dwPrevPhys= 0;

    DWORD dwAddr= dwVirtbase;
    DWORD pidx= 0;
    for (int i=0 ; i<nentries ; i++)
    {
        DWORD pe= ptbl[pidx];

        DWORD dwCurPhys= 0;
        bool bHasPhysAddr= false;
        bool bEndBlock= false;

        switch (pe&3) {
            case 0:  // ignore entry
                bEndBlock= true;
                break;
            case 1:  // large page descriptor
                dwCurPhys= pe&0xffff0000;
                bHasPhysAddr= true;
                break;
            case 2:  // small page descriptor
                dwCurPhys= pe&0xfffff000;
                bHasPhysAddr= true;
                break;
            case 3:  // tiny page descriptor
                dwCurPhys= pe&0xfffffc00;
                bHasPhysAddr= true;
                break;
        }
        if (dwCurPhys-dwPrevPhys!=pagesize)
            bEndBlock= true;

        if (bStarted && bEndBlock) {
            debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
            bStarted= false;
        }
        if (bHasPhysAddr) {
            if (!bStarted) {
                bStarted= true;
                dwStartPhys= dwCurPhys;
                dwStartVirt= dwAddr;
            }
            dwPrevPhys= dwCurPhys;
        }

        dwAddr+=pagesize;
        pidx++;
    }
    if (bStarted) {
        debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
        bStarted= false;
    }

}
void SummarizePageTable()
{
    DWORD *ptbl= (DWORD*)0xfffd0000;
    DWORD pagesize= 0x100000;

    bool bStarted= false;
    DWORD dwStartVirt= 0;
    DWORD dwStartPhys= 0;
    DWORD dwPrevPhys= 0;

    DWORD dwAddr= 0;
    DWORD pidx= 0;
    do {
        DWORD pe= ptbl[pidx];

        DWORD dwCurPhys= 0;
        DWORD dwTlbPhys= 0;
        DWORD dwTlbPagesize= 0;
        bool bHasPhysAddr= false;
        bool bEndBlock= false;
        bool bHasTlb2= false;

        switch (pe&3) {
            case 0:  // ignore entry
                bEndBlock= true;
                break;
            case 1:  // coarse tlb entry
                dwTlbPhys= pe&0xfffffc00;
                dwTlbPagesize= 0x1000;
                bHasTlb2= true;
                bEndBlock= true;
                break;
            case 2:  // section descriptor
                dwCurPhys= pe&0xfff00000;
                bHasPhysAddr= true;
                break;
            case 3:  // fine tlb entry
                dwTlbPhys= pe&0xfffff000;
                dwTlbPagesize= 0x400;
                bHasTlb2= true;
                bEndBlock= true;
                break;
        }
        if (dwCurPhys-dwPrevPhys!=pagesize)
            bEndBlock= true;

        if (bStarted && bEndBlock) {
            debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
            bStarted= false;
        }
        if (bHasTlb2) {
            SummarizeTLB2(dwAddr, dwTlbPhys, dwTlbPagesize, pagesize/dwTlbPagesize);
        }
        if (bHasPhysAddr) {
            if (!bStarted) {
                bStarted= true;
                dwStartPhys= dwCurPhys;
                dwStartVirt= dwAddr;
            }
            dwPrevPhys= dwCurPhys;
        }

        dwAddr+=pagesize;
        pidx++;
    } while (dwAddr);
    if (bStarted) {
        debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
        bStarted= false;
    }
}
void SummarizeSections()
{
    bool wince3x= GetWinceVersion() < 4 ;
    DWORD pagesize= 0x1000;

    DWORD dwStartPhys=0;
    DWORD dwStartVirt=0;
    DWORD dwPrevPhys=0;
    bool bStarted= false;
    DWORD dwAddr;
    for (dwAddr= 0 ; 
            dwAddr<(wince3x?0x80000000:0xc4000000) ; 
            dwAddr += (!wince3x && dwAddr==0x80000000) ? 0x42000000 : pagesize) {
        SECTION *pscn = (dwAddr & 0x80000000)? (SECTION*)KInfoTable[KINX_NKSECTION]: SectionTable[dwAddr>>VA_SECTION];
        DWORD ixBlock = (dwAddr >> VA_BLOCK) & BLOCK_MASK;
        DWORD ixPage = (dwAddr >> VA_PAGE) & PAGE_MASK;
        MEMBLOCK *pmb = (*pscn)[ixBlock];
        DWORD dwPhys= 0;
        bool bEndBlock =  false;
        bool bHasPhysAddr= false;
        if (pmb==NULL_BLOCK || pmb==RESERVED_BLOCK) {
            bEndBlock= true;
        }
        else {
            DWORD dwPageentry= GetPagesList(pmb)[ixPage];
            if (dwPageentry==0xfffffff0 || dwPageentry==0 ) 
                bEndBlock= true;
            else {
                dwPhys= GetPagesList(pmb)[ixPage]&0xfffff000;
                bHasPhysAddr= true;
                if (dwPhys-dwPrevPhys!=pagesize)
                    bEndBlock= true;
            }
        }
        if (bEndBlock && bStarted) {
            debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
            bStarted= false;
        }

        if (bHasPhysAddr) {
            if (!bStarted) {
                bStarted= true;
                dwStartPhys= dwPhys;
                dwStartVirt= dwAddr;
            }
            dwPrevPhys= dwPhys;
        }
    }
    if (bStarted) {
        debug("v%08lx-%08lx -> p%08lx-%08lx\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize);
        bStarted= false;
    }
}

void DumpKernelInfo()
{
	struct KDataStruct *k= (struct KDataStruct *)0xffffc800;

int i;
debug("%-64s %08lx\n", "0x000 Current thread local storage pointer", k->lpvTls);
debug("%-64s SH_WIN32     %08lx\n", "", k->ahSys[SH_WIN32    ]);
debug("%-64s SH_CURTHREAD %08lx\n", "", k->ahSys[SH_CURTHREAD]);
debug("%-64s SH_CURPROC   %08lx\n", "", k->ahSys[SH_CURPROC  ]);
debug("ahSys  ");
    for (i=SH_CURPROC+1 ; i<NUM_SYS_HANDLES ; i++) debug(" %08lx", k->ahSys[i]);
debug("\n");

debug("%-64s %d\n", "0x084 reschedule flag", k->bResched);
debug("%-64s %d\n", "0x085 kernel exception nesting", k->cNest);
debug("%-64s %d\n", "0x086 TRUE during power off processing", k->bPowerOff);
debug("%-64s %d\n", "0x087 TRUE if profiling enabled", k->bProfileOn);
#if _WIN32_WCE==300
debug("%-64s %08lx\n", "0x088 Page Table Descriptor", k->ptDesc);
#endif
debug("%-64s %08lx\n", "0x08c was DiffMSec", k->rsvd2);
debug("%-64s %08lx\n", "0x090 ptr to current PROCESS struct", k->pCurPrc);
debug("%-64s %08lx\n", "0x094 ptr to current THREAD struct", k->pCurThd);
debug("%-64s %08lx\n", "0x098 ", k->dwKCRes);
debug("%-64s %08lx\n", "0x09c handle table base address", k->handleBase);
debug("%-64s ", "0x0a0 section table for virtual memory");
    for (i=0 ; i<64 ; i++) debug(" %08lx", k->aSections[i]);
debug("\n");

debug("%-64s ", "0x1a0, 0x220 device events ");
#if SYSINTR_MAX_DEVICES==0x40
    for (i=0 ; i<SYSINTR_MAX_DEVICES ; i++) debug(" %08lx", k->alpeIntrEvents[i]);
#else
    for (i=0 ; i<SYSINTR_MAX_DEVICES ; i++) debug(" %08lx:%08lx", k->alpvIntrData[i], k->alpeIntrEvents[i]);
#endif
debug("\n");

debug("%-64s %08lx\n", "0x2a0 direct API return address for kernel mode", k->pAPIReturn);
debug("%-64s %08lx\n", "0x2a4 ptr to MemoryMap array", k->pMap);
debug("%-64s %08lx\n", "0x2a8 !0 when in debugger", k->dwInDebugger);

//debug("%-64s long\n", "0x2ac - padding", k->alPad[21]);
debug("%-64s %08lx\n", "aInfo[KINX_PROCARRAY]: address of process array", k->aInfo[KINX_PROCARRAY]);
debug("%-64s %08lx\n", "aInfo[KINX_PAGESIZE]: system page size", k->aInfo[KINX_PAGESIZE]);
debug("%-64s %08lx\n", "aInfo[KINX_PFN_SHIFT]: shift for page # in PTE", k->aInfo[KINX_PFN_SHIFT]);
debug("%-64s %08lx\n", "aInfo[KINX_PFN_MASK]: mask for page # in PTE", k->aInfo[KINX_PFN_MASK]);
debug("%-64s %08lx\n", "aInfo[KINX_PAGEFREE]: # of free physical pages", k->aInfo[KINX_PAGEFREE]);
debug("%-64s %08lx\n", "aInfo[KINX_SYSPAGES]: # of pages used by kernel", k->aInfo[KINX_SYSPAGES]);
debug("%-64s %08lx\n", "aInfo[KINX_KHEAP]: ptr to kernel heap array", k->aInfo[KINX_KHEAP]);
debug("%-64s %08lx\n", "aInfo[KINX_SECTIONS]: ptr to SectionTable array", k->aInfo[KINX_SECTIONS]);
debug("%-64s %08lx\n", "aInfo[KINX_MEMINFO]: ptr to system MemoryInfo struct", k->aInfo[KINX_MEMINFO]);
debug("%-64s %08lx\n", "aInfo[KINX_MODULES]: ptr to module list", k->aInfo[KINX_MODULES]);
debug("%-64s %08lx\n", "aInfo[KINX_DLL_LOW]: lower bound of DLL shared space", k->aInfo[KINX_DLL_LOW]);
debug("%-64s %08lx\n", "aInfo[KINX_NUMPAGES]: total # of RAM pages", k->aInfo[KINX_NUMPAGES]);
debug("%-64s %08lx\n", "aInfo[KINX_PTOC]: ptr to ROM table of contents", k->aInfo[KINX_PTOC]);
debug("%-64s %08lx\n", "aInfo[KINX_KDATA_ADDR]: kernel mode version of KData", k->aInfo[KINX_KDATA_ADDR]);
debug("%-64s %08lx\n", "aInfo[KINX_GWESHEAPINFO]: Current amount of gwes heap in use", k->aInfo[KINX_GWESHEAPINFO]);
debug("%-64s %08lx\n", "aInfo[KINX_TIMEZONEBIAS]: Fast timezone bias info", k->aInfo[KINX_TIMEZONEBIAS]);
debug("%-64s %08lx\n", "aInfo[KINX_PENDEVENTS]: bit mask for pending interrupt events", k->aInfo[KINX_PENDEVENTS]);
debug("%-64s %08lx\n", "aInfo[KINX_KERNRESERVE]: number of kernel reserved pages", k->aInfo[KINX_KERNRESERVE]);
debug("%-64s %08lx\n", "aInfo[KINX_API_MASK]: bit mask for registered api sets", k->aInfo[KINX_API_MASK]);

#if _WIN32_WCE==300
debug("%-64s %08lx\n", "aInfo[KINX_NLS_OCP]: Current OEM code page", k->aInfo[KINX_NLS_OCP]);
debug("%-64s %08lx\n", "aInfo[KINX_NLS_ACP]: Current ANSI code page", k->aInfo[KINX_NLS_ACP]);
debug("%-64s %08lx\n", "aInfo[KINX_NLS_LOC]: Current NLS locale", k->aInfo[KINX_NLS_LOC]);
#else
debug("%-64s %08lx\n", "aInfo[KINX_NLS_CP]: hiword OEM code page, loword ANSI code page", k->aInfo[KINX_NLS_CP]);
debug("%-64s %08lx\n", "aInfo[KINX_NLS_SYSLOC]: Default System locale", k->aInfo[KINX_NLS_SYSLOC]);
debug("%-64s %08lx\n", "aInfo[KINX_NLS_USERLOC]: Default User locale", k->aInfo[KINX_NLS_USERLOC]);
#endif

debug("%-64s %08lx\n", "aInfo[KINX_HEAP_WASTE]: Kernel heap wasted space", k->aInfo[KINX_HEAP_WASTE]);
debug("%-64s %08lx\n", "aInfo[KINX_DEBUGGER]: For use by debugger for protocol communication", k->aInfo[KINX_DEBUGGER]);
debug("%-64s %08lx\n", "aInfo[KINX_APISETS]: APIset pointers", k->aInfo[KINX_APISETS]);
debug("%-64s %08lx\n", "aInfo[KINX_MINPAGEFREE]: water mark of the minimum number of free pages", k->aInfo[KINX_MINPAGEFREE]);
debug("%-64s %08lx\n", "aInfo[KINX_CELOGSTATUS]: CeLog status flags", k->aInfo[KINX_CELOGSTATUS]);
debug("%-64s %08lx\n", "aInfo[KINX_NKSECTION]: Address of NKSection", k->aInfo[KINX_NKSECTION]);
#ifdef KINX_PWR_EVTS
debug("%-64s %08lx\n", "aInfo[KINX_PWR_EVTS]: Events to be set after power on", k->aInfo[KINX_PWR_EVTS]);
#endif
debug("%-64s %08lx\n", "aInfo[29]: ", k->aInfo[29]);
debug("%-64s %08lx\n", "aInfo[30]: ", k->aInfo[30]);
debug("%-64s %08lx\n", "aInfo[31]: last entry of KINFO -- signature when NK is ready", k->aInfo[31]);

CINFO **apisets= (CINFO**)k->aInfo[KINX_APISETS];
for (i=0 ; i<32 ; i++)
	if (apisets[i])
		RegisterCInfo(apisets[i], i);

debug("k->aInfo  ");
    for (i=KINX_APISETS+1 ; i<32 ; i++) debug(" %08lx", k->aInfo[i]);
debug("\n");
MEMORYINFO *pmi= (MEMORYINFO*)k->aInfo[KINX_MEMINFO];
debug("meminfo: kdata=%08lx-%08lx  #free entries: %d\n",
        pmi->pKData, pmi->pKEnd, pmi->cFi);

// debug("------------------sections\n");
// // section 0      00000000-02000000: current process
// // section 1      02000000-04000000: module section
// // section 2-32   04000000-42000000: processes
// // section 33-62  42000000-7e000000: filemappings
// // section 63     7e000000-80000000: resource section
//     for (i=0 ; i<64 ; i++)  {
//         DumpSection(i<<VA_SECTION, k->aSections[i]);
//     }
// debug("------------------kernel section\n");
//     DumpSection(0xc2000000, (SECTION*)k->aInfo[KINX_NKSECTION]);

/*
debug("------------------section summary\n");
    SummarizeSections();
debug("------------------pagetable summary\n");
    SummarizePageTable();
*/
}

int WINAPI WinMain(	HINSTANCE hInstance,
					HINSTANCE hPrevInstance,
					LPTSTR    lpCmdLine,
					int       nCmdShow)
{
    DebugSetLogfile("testpi.log");
    DebugOutputDebugString();
/*
    // create some open handles
    HANDLE hFile= CreateFile(L"\\windows\\notes.exe", GENERIC_READ, 0,NULL, OPEN_EXISTING, 0, NULL);
    HKEY hkey;
    DWORD disp;
    LONG res= RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"Software", 0, L"??", 0, KEY_WRITE, NULL, &hkey, &disp);
    debug("filehandle=%08lx reghandle=%08lx\n", hFile, hkey);
*/

    BOOL bMode = SetKMode(TRUE);
    DWORD dwPerm = SetProcPermissions(0xFFFFFFFF);

    //g_hFilesysProc= GetProcessHandle(L"filesys.exe");
    //g_hDeviceProc= GetProcessHandle(L"device.exe");

debug("------------------kernel info\n");
	DumpKernelInfo();

debug("------------------testhandle\n");
	testhandle(hInstance);

debug("------------------cinfo\n");
	DumpCInfoMap();

	testtoolhelp();

    SetProcPermissions(dwPerm);
    SetKMode(bMode);

/*
	ThreadInfo ti(GetCurrentThread());

	DWORD tMax= 2048;

	ti.GetThreadInfo();

	for (DWORD iSleep= 0 ; iSleep < tMax ; iSleep = iSleep?2*iSleep:1)
	{
		DWORD t0= GetTickCount();

		while(GetTickCount()-t0 < tMax) Sleep(iSleep);

		ti.GetThreadInfo();

		debug("%6d : k%5d u%5d - k%5d u%5d\n", 
			iSleep,
			ti.m_promileKernelRecent, ti.m_promileKernelTotal, ti.m_promileUserRecent, ti.m_promileUserTotal);
	}
*/
	return 0;
}
