/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id$ */ #include #include "cever_deps.h" #include "kernelmisc.h" #include "stringutils.h" #include "cenk.h" #include "debug.h" //#include "itsutils.h" #include "MemoryUsage.h" /* differences in struct sizes - these are certainly different between os versions there may be more differences. | 300 | 420 | 501 -----------+------+-----+---- CPUCONTEXT | 68 | 240 | 240 CALLSTACK | 20 | 28 | 28 THREAD | 380 | 572 | 576 e32_lite | 72 | 72 | 84 - has extra timestamp + extra info record PROCESS | 176 | 216 | 240 FSMAP | 44 | 48 | 48 Module | 208 | 216 | 228 FreeInfo | 12 | 16 | 16 MemBlock | 76 | 16 | 16 EVENT | 148 | 156 | 156 MUTEX | 164 | 168 | 168 SEMAPHORE | 152 | 156 | 156 CRIT | 160 | 164 | 164 e32_rom | 108 | 108 | 112 */ bool dumpstructsizes_forver() { debug("%d: FILETIME=%d CPUCONTEXT=%d CALLSTACK=%d THREAD=%d openexe_t=%d info=%d e32_lite=%d o32_lite=%d PGPOOL_Q=%d PROCESS=%d CINFO=%d HDATA=%d fsopendev_t=%d fsdev_t=%d FSMAP=%d PROXY=%d Module=%d Name=%d MemoryInfo=%d FreeInfo=%d MemBlock=%d APISET=%d EVENT=%d MUTEX=%d SEMAPHORE=%d CLEANEVENT=%d CRIT=%d CRITICAL_SECTION=%d ROMHDR=%d COPYentry=%d FILESentry=%d TOCentry=%d e32_rom=%d o32_rom=%d IMAGE_DEBUG_DIRECTORY=%d e32_exe=%d o32_obj=%d\n", _WIN32_WCE, sizeof(FILETIME) , sizeof(CPUCONTEXT) , sizeof(CALLSTACK) , sizeof(THREAD) , sizeof(openexe_t) , sizeof(info) , sizeof(e32_lite) , sizeof(o32_lite) , sizeof(PGPOOL_Q) , sizeof(PROCESS) , sizeof(CINFO) , sizeof(HDATA) , sizeof(fsopendev_t) , sizeof(fsdev_t) , sizeof(FSMAP) , sizeof(PROXY) , sizeof(Module) , sizeof(Name) , sizeof(MemoryInfo) , sizeof(FreeInfo) , sizeof(MemBlock) , sizeof(APISET) , sizeof(EVENT) , sizeof(MUTEX) , sizeof(SEMAPHORE) , sizeof(CLEANEVENT) , sizeof(CRIT) , sizeof(CRITICAL_SECTION) , sizeof(ROMHDR) , sizeof(COPYentry) , sizeof(FILESentry) , sizeof(TOCentry) , sizeof(e32_rom) , sizeof(o32_rom) , sizeof(IMAGE_DEBUG_DIRECTORY) , sizeof(e32_exe) , sizeof(o32_obj)); return true; } // c:\local\wince300\PRIVATE/WINCEOS/COREOS/NK/INC/kernel.h // //bool GetProcessTimes_forver(DWORD pid, DWORD *ptKernel, DWORD *ptUser) //{ // HDATA *hdata= cvHandle2HDataPtr((HANDLE)pid); // // PROCESS *pproc= (PROCESS *)hdata->pvObj; // // DWORD tKernel=0; // DWORD tUser=0; // // THREAD *pth= pproc->pTh; // while(pth) // { // tKernel += pth->dwKernTime; // tUser += pth->dwUserTime; // // pth= pth->pNextInProc; // } // *ptKernel= tKernel; // *ptUser= tUser; // return true; //} //const WCHAR *GetProcessCommandLine_forver(DWORD pid) //{ // HDATA *hdata= cvHandle2HDataPtr((HANDLE)pid); // // PROCESS *pproc= (PROCESS *)hdata->pvObj; // // return pproc->pcmdline; //} DWORD GetThreadStackStart_forver(THREAD *thread) { #if _WIN32_WCE==300 return thread->dwStackBase+thread->dwStackBound; #else return thread->dwOrigBase+thread->dwOrigStkSize; #endif } // ... called from debugger int AddThreadInfo_forver(char *buf, int bufsize, DWORD pid, DWORD tid, bool needhexdump) { int n=0; HDATA *hdp= cvHandle2HDataPtr((HANDLE)pid); PROCESS *proc= (PROCESS *)hdp->pvObj; HDATA *hdt= cvHandle2HDataPtr((HANDLE)tid); THREAD *thread= (THREAD*)hdt->pvObj; CPUCONTEXT *ctx= &(thread->ctx); n+= _snprintf(buf+n, bufsize-n, "PC=%08lx LR=%08lx SP=%08lx R0-12: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", ctx->Pc, ctx->Lr, ctx->Sp, ctx->R0, ctx->R1, ctx->R2, ctx->R3, ctx->R4, ctx->R5, ctx->R6, ctx->R7, ctx->R8, ctx->R9, ctx->R10, ctx->R11, ctx->R12); printf("ITSUTILS debugger stackdump: valid:%d, dump:%d sp=%08x..%08x, bufp=%08x, size=%08x\n", isValidPtr((DWORD)MapPtrWithBits(ctx->Sp, proc->dwVMBase)), needhexdump, ctx->Sp, GetThreadStackStart(thread), n, bufsize); if (isValidPtr((DWORD)MapPtrWithBits(ctx->Sp, proc->dwVMBase))) { if (needhexdump) n+= _snprintf(buf+n, bufsize-n, "stack: %s\n", hexdump((BYTE*)ctx->Sp, (GetThreadStackStart(thread)-ctx->Sp)/4, 4).c_str()); } return n; } //---------------------------------------------------------- bool GetProcessUsageList_forver(ProcSummaryInfoVector &list) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; list.resize(MAX_PROCESSES); for (int i=0 ; ipcstkTop ; p ; p= p->pcstkNext) { #if _WIN32_WCE==300 debug("callstack(%08lx/h%08lx) addr=%08lx proc=%08lx(h%08lx)\n", t, t->hTh, p->retAddr, p->pprcLast?p->pprcLast->hProc:0); #else debug("callstack(%08lx/h%08lx) addr=%08lx sp=%08lx proc=%08lx(h%08lx)\n", t, t->hTh, p->retAddr, p->dwPrevSP, p->pprcLast?p->pprcLast->hProc:0); #endif } return true; } bool dump_proxy_list_forver(PROXY *proxy) { bool bFirst= true; for (PROXY *p= proxy ; p && (bFirst || p!=proxy) ; p= p->pThLinkNext, bFirst= false) { if (p==(PROXY*)0xffffc800 || IsBadReadPtr((void*)p, sizeof(PROXY))) { debug(">???? prox=%08lx\n", p); break; } debug("%08lx - o=%08lx t=%d p=%02x n=%d pTH=%08lx:%08lx\n", p, p->pObject, p->bType, p->prio, p->wCount, p->pTh, (p->pTh) ? p->pTh->hTh : INVALID_HANDLE_VALUE); } return true; } bool dumplocks_forver(THREAD *t) { if (t->pProxList) { debug("%08lx is blocking these:\n", t->hTh, t); dump_proxy_list(t->pProxList); } if (t->lpProxy) { debug("%08lx is blocked by:\n", t->hTh); dump_proxy_list(t->lpProxy); } if (t->lpCritProxy) { debug("%08lx crit proxy:\n", t->hTh); dump_proxy_list(t->lpCritProxy); } if (t->lpPendProxy) { debug("%08lx pending proxies:\n", t->hTh); dump_proxy_list(t->lpPendProxy); } return true; } bool GetThreadUsageList_forver(ThreadSummaryInfoVector &list, bool resolve_modulenames) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; for (int i=0 ; ipTh->pPrevInProc == NULL // the list iterates over pNextInProc until NULL is found, // so it is not a circular list. // but i check for a circular list anyway, just to be sure int j=0; THREAD *pt; for (pt=procarray[i].pTh ; pt && (j==0 || pt!=procarray[i].pTh) ; pt= pt->pNextInProc, j++) { /* #if _WIN32_WCE==300 debug("thread %08lx - %08lx: stack=%08lx-%08lx\n", pt->hTh, pt, pt->dwStackBase, pt->dwStackBase+pt->dwStackBound); #else debug("thread %08lx - %08lx: stack=%08lx-%08lx\n", pt->hTh, pt, pt->dwOrigBase, pt->dwOrigBase+pt->dwOrigStkSize); #endif dumplocks(pt); dumpcallstack(pt); */ list.resize(list.size()+1); ThreadSummaryInfo &ts= list.back(); if (pt->pOwnerProc==NULL) { debug("ownerproc==NULL\n"); } else { ts.hProc = pt->pOwnerProc->hProc; } ts.hThread = pt->hTh; ts.tKernel = pt->dwKernTime; ts.tUser = pt->dwUserTime; ts.dwStartAddr= pt->dwStartAddr; ts.dwCurPC= pt->ctx.Pc; ts.dwCurLR= pt->ctx.Lr; ts.dwCurSP= pt->ctx.Sp; ts.szModname[0]= 0; ts.baseprio= pt->bBPrio; ts.curprio= pt->bCPrio; } if (pt) debug("GetThreadUsageList:NOTE: this device uses a circular list for threads\n"); } // else // debug("ignoring process %d : num %d h %08lx\n", i, procarray[i].procnum, procarray[i].hProc); } if (resolve_modulenames) { ModuleInfoMap mimap; if (CreateModuleInfoMap(mimap)) for (unsigned i=0 ; i=400 || (IsSecureVa(dwAddr)) // IsSecureVa from pkfuncs.h #endif ) { // fedcba9876543210fedcba9876543210 // 0ssssssbbbbbbbbbpppp............ // // sectiontable[sssssss]->memblock[bbbbbbbbb]->page[pppp] // SECTION *pscn = #if _WIN32_WCE>=400 (dwAddr & 0x80000000) ? (SECTION*)KInfoTable[KINX_NKSECTION] : #endif SectionTable[dwAddr>>VA_SECTION]; DWORD ixBlock = (dwAddr >> VA_BLOCK) & BLOCK_MASK; DWORD ixPage = (dwAddr >> VA_PAGE) & PAGE_MASK; MEMBLOCK *pmb = (*pscn)[ixBlock]; if (pmb==NULL_BLOCK || pmb==RESERVED_BLOCK) return INVALID_PHYSICAL_ADDRESS; if (pmb->aPages[ixPage]==0 || pmb->aPages[ixPage]==BAD_PAGE) return INVALID_PHYSICAL_ADDRESS; return (pmb->aPages[ixPage]&0xfffff000) | (dwAddr&0xfff); } else { DWORD ixPage= (dwAddr>>20)&0xfff; DWORD dwEntry= FirstPT[ixPage]; // FirstPT is defined in nkarm.h if ((dwEntry&3)==2) { // fedcba9876543210fedcba9876543210 // ssssssssssss.................... index in 1st ptbl // // section descriptor return (dwEntry&0xfff00000)|(dwAddr&0xfffff); } else if ((dwEntry&0xfffff)==0) { return INVALID_PHYSICAL_ADDRESS; } else if ((dwEntry&3)==1) { // fedcba9876543210fedcba9876543210 // ............22222222............ index in 2nd ptbl // coarse page table entry DWORD phys_2nd_tlb= dwEntry&~0x3f; DWORD virt_2nd_tlb= PhysToVirtUC(phys_2nd_tlb); DWORD ix2ndPage= (dwAddr>>12)&0xff; DWORD dw2ndEntry= ((DWORD*)virt_2nd_tlb)[ix2ndPage]; if ((dw2ndEntry&3)==1) { // large page // // fedcba9876543210fedcba9876543210 // ............22222222............ index in 2nd ptbl // ................llllllllllllllll large page adress mask // // note that there is an overlap between used addressbits here // and used bits to index ix2ndpage. // -> virt_2nd_tlb[ix2ndPage&~0xf+i] for i= 0 ..15 must be equal return (dw2ndEntry&0xffff0000)|(dwAddr&0xffff); } else if ((dw2ndEntry&3)==2) { // small page // // fedcba9876543210fedcba9876543210 // ............22222222............ index in 2nd ptbl // ....................ssssssssssss small page adress mask // return (dw2ndEntry&0xfffff000)|(dwAddr&0xfff);; } // tiny pages should only occur in fine 2nd level pages return INVALID_PHYSICAL_ADDRESS; } else if ((dwEntry&3)==3) { // fedcba9876543210fedcba9876543210 // ............2222222222.......... index in 2nd ptbl // fine page table entry DWORD phys_2nd_tlb= dwEntry&~0xfff; DWORD virt_2nd_tlb= PhysToVirtUC(phys_2nd_tlb); DWORD ix2ndPage= (dwAddr>>10)&0x3ff; DWORD dw2ndEntry= ((DWORD*)virt_2nd_tlb)[ix2ndPage]; if ((dw2ndEntry&3)==1) { // large page // // fedcba9876543210fedcba9876543210 // ............2222222222.......... index in 2nd ptbl // ................llllllllllllllll large page adress mask // return (dw2ndEntry&0xffff0000)|(dwAddr&0xffff); } else if ((dw2ndEntry&3)==2) { // small page // // fedcba9876543210fedcba9876543210 // ............2222222222.......... index in 2nd ptbl // ....................ssssssssssss small page adress mask // return (dw2ndEntry&0xfffff000)|(dwAddr&0xfff);; } else if ((dw2ndEntry&3)==3) { // tiny page // // fedcba9876543210fedcba9876543210 // ............2222222222.......... index in 2nd ptbl // ......................tttttttttt tiny page address mask // return (dw2ndEntry&0xfffffc00)|(dwAddr&0x3ff);; } return INVALID_PHYSICAL_ADDRESS; } return INVALID_PHYSICAL_ADDRESS; } } PROCESS *FindProcessForName_forver(const TCHAR *procname) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; for (int i=0 ; iBasePtr; if (base>=0xc2000000 && base<0xc4000000) base-=0xc2000000; return base; } bool FillModuleInfo_forver(ModuleInfo &mi, const struct Module *m) { mi.csegbase= m->e32.e32_vbase; mi.csegsize= m->e32.e32_vsize; mi.name= ToString(m->lpszModName); mi.membase= (DWORD)m->BasePtr; mi.usagemask= m->inuse; // find largest read/write data page mi.dsegbase= 0; mi.dsegsize= 0; //debug("module %08lx %ls\n", ent->dwVBase, ent->szModuleName); for (size_t i=0 ; ie32.e32_objcnt ; i++) { struct o32_lite *o32= &(m->o32_ptr[i]); //debug("o32 VA%08lx RA%08lx DP%08lx A%08lx F%08lx l=%08lx\n", o32->o32_rva, o32->o32_realaddr, o32->o32_dataptr, o32->o32_access, o32->o32_flags, o32->o32_vsize); if (o32->o32_access==PAGE_READWRITE && (mi.dsegsize==0 || mi.dsegsize < o32->o32_vsize)) { mi.dsegbase= o32->o32_realaddr; mi.dsegsize= o32->o32_vsize; } } //debug("mod %08lx %08lx-%08lx %08lx-%08lx %hs\n", mi.membase, mi.csegbase, mi.csegbase+mi.csegsize, mi.dsegbase, mi.dsegbase+mi.dsegsize, mi.name.c_str()); return true; } bool GetProcessList_forver(CeProcessList& list) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; for (int i=0 ; icntUsage= pp->cntUsage; cepe->dwProcessID= (DWORD)pp->hProc; //cepe->dwDefaultHeapID= pp->th32DefaultHeapID; //cepe->dwModuleID= pp->th32ModuleID; //cepe->cntThreads= GetProcessThreadSummary(pp, &cepe->dwKernelTime, &cepe->dwUserTime); //cepe->dwParentProcessID= pp->th32ParentProcessID; //cepe->dwFlags= pp->dwFlags; cepe->dwMemoryBase= pp->dwVMBase; cepe->dwAccessKey= pp->aky; wcsncpy(cepe->szExeFile, pp->lpszProcName, MAX_PATH); wcsncpy(cepe->szCmdLine, pp->pcmdline, MAX_PATH); // this is optional, since the the heap of gwes.exe may take upto 5 seconds to scan. // if (pbInput->bIncludeHeapUsage) cepe->dwMemoryUsage= CalcMemoryUsageForSection(pp->dwVMBase>>25); } } return true; } int GetProcessThreadSummary_forver(PROCESS *pp, DWORD *ptKernel, DWORD *ptUser) { int count=0; DWORD tKernel=0; DWORD tUser=0; for (THREAD *pt= pp->pTh ; pt && (count==0 || pt!=pp->pTh) ; pt=pt->pNextInProc) { tKernel += pt->dwKernTime; tUser += pt->dwUserTime; count++; } *ptKernel= tKernel; *ptUser= tUser; return count; } void dumpdllinfo_forver(HMODULE hLib) { MODULE *m= (MODULE*)hLib; debug("module=%08lx, name=%08lx, use=%08lx base=%08lx\n", m, m->lpszModName, m->inuse, m->BasePtr); debug("cseg:%08lx/%08lx : %d\n", m->e32.e32_vbase, m->e32.e32_vsize, IsBadReadPtr((void*)m->e32.e32_vbase, m->e32.e32_vsize)); for (unsigned i=0 ; ie32.e32_objcnt ; i++) { struct o32_lite *o32= &(m->o32_ptr[i]); debug("dseg[%d] : %08lx/%08lx : %d\n", i, o32->o32_realaddr, o32->o32_vsize, IsBadReadPtr((void*)o32->o32_realaddr, o32->o32_vsize)); } StringList ref; for (int i=0 ; i<32 ; i++) ref.push_back(stringformat("%2d", m->refcnt[i])); debug("ref: %s\n", JoinStringList(ref, "").c_str()); } bool GetModuleVirtualCodeRange_forver(MODULE *m, DWORD *vbase, DWORD *vsize) { for (int i=0 ; ie32.e32_objcnt ; i++) { if (m->o32_ptr[i].o32_flags&IMAGE_SCN_CNT_CODE) { *vbase= m->o32_ptr[i].o32_realaddr; *vsize= m->o32_ptr[i].o32_vsize; return true; } } return false; } void GetModuleVirtualDataRange_forver(MODULE *m, DWORD *vbase, DWORD *vsize) { *vsize=0; *vbase=0; for (unsigned i=0 ; ie32.e32_objcnt ; i++) { struct o32_lite *o32= &(m->o32_ptr[i]); if (o32->o32_access==PAGE_READWRITE && (*vsize==0 || *vsize < o32->o32_vsize)) { *vbase= o32->o32_realaddr; *vsize= o32->o32_vsize; } } } void GetProcessVirtualRange_forver(PROCESS *p, DWORD *vbase, DWORD *vsize) { *vbase= p->e32.e32_vbase; *vsize= p->e32.e32_vsize; } bool isValidPtr_forver(DWORD dwAddr) { return VirtToPhys(dwAddr)!=INVALID_PHYSICAL_ADDRESS; } bool CreateModuleInfoMap_forver(ModuleInfoMap& map) { for (MODULE *m= (MODULE*)KData.aInfo[KINX_MODULES]; m ; m=m->pMod) { DWORD vbase= GetModuleMembase(m); FillModuleInfo(map[vbase], m); } return true; }