/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: cever_deps.cpp 1756 2008-03-19 13:40:04Z itsme $ */ #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 test_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; //} // ... called from debugger int AddThreadInfo_forver(char *buf, int bufsize, DWORD pid, DWORD tid) { 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); if (isValidPtr((DWORD)MapPtrWithBits(ctx->Sp, proc->dwVMBase))) { #if _WIN32_WCE==300 int maxsp= thread->dwStackBase+thread->dwStackBound- ctx->Sp; #else int maxsp= thread->dwOrigBase+thread->dwOrigStkSize - ctx->Sp; #endif n+= _snprintf(buf+n, bufsize-n, "stack: %s\n", hexdump((BYTE*)ctx->Sp, maxsp/4, 4).c_str()); } return n; } //---------------------------------------------------------- bool GetProcessUsageList_forver(GetProcessUsageListResult *pOut) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; for (int i=0 ; i<32 ; i++) { if (procarray[i].dwVMBase) { // NOTE: process->pTh->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; ProcSummaryInfo &ps= pOut->list[procarray[i].procnum]; ps.nThreads= GetProcessThreadSummary(procarray+i, &ps.tKernel, &ps.tUser); ps.hProc= procarray[i].hProc; } } return true; } bool dumpcallstack_forver(THREAD *t) { for (CALLSTACK *p = t->pcstkTop ; 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(GetThreadUsageListResult *pOut, bool resolve_modulenames) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; int threadnr= 0; for (int i=0 ; i<32 ; i++) { if (procarray[i].dwVMBase) { // NOTE: process->pTh->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 ; (threadnrpNextInProc, 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); */ ThreadSummaryInfo &ts= pOut->list[threadnr++]; 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 (threadnr>=MAX_THREADS) { debug("too many threads, itsutils can handle max %d threads\n", MAX_THREADS); break; } else 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); } pOut->nThreads= threadnr; if (resolve_modulenames) { ModuleInfoMap mimap; if (CreateModuleInfoMap(mimap)) for (int i=0 ; ilist[i]; FindModuleNameForProcessAddress(mimap, (DWORD)ts.hProc, ts.dwStartAddr, ts.szModname, 255); } } return true; } /* at 0xffffc8a0 there is a list of 64 section pointers unused sections all contain the same ptr to a special 'NullSection', containing only NULs each section is a list of 512 ptrs to MEMBLOCKs there are 2 special memblock ptr values: 0x00000000 - null 0x00000001 - reserved each memblock contains 12 bytes of info + a ptr to a pagelist each pagelist contains 16 pagetable entries there are 2 special pagetable entries: 0x00000000 - unused 0xfffffff0 - BAD_PAGE of each entry bits 31-12 point to a physical memory page the low 12 bits can contain the following values: 0x00e - readonly 0xffe - readwrite */ // this function is different is os version dependent, // since the nksection/securesection was introduced in wince4 // and aPages was an array in wince3, and a ptr to a memblock array in wince4 DWORD VirtToPhys_forver(DWORD dwAddr) { if (dwAddr==0) return INVALID_PHYSICAL_ADDRESS; if ((dwAddr<0x80000000) #if _WIN32_WCE>=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; } } static bool match_process_name(const TCHAR *a, const TCHAR *b) { while (*a && *b && *a!='.' && *b!='.' && tolower(*a)==tolower(*b)) { a++; b++; } return (*a==0 || *a=='.') && (*b==0 || *b=='.'); } int FindProcessSlotForName_forver(const TCHAR *procname) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; for (int i=0 ; i<32 ; i++) { if (procarray[i].dwVMBase) { if (match_process_name(procarray[i].lpszProcName, procname)) { return i; } } } return -1; } DWORD getProcessSlotVMBase_forver(int slot) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; return procarray[slot].dwVMBase; } HANDLE getProcessSlotHandle_forver(int slot) { PROCESS *procarray= (PROCESS*)KData.aInfo[KINX_PROCARRAY]; return procarray[slot].hProc; } DWORD GetModuleMembase_forver(const struct Module *m) { DWORD base= (DWORD)m->BasePtr; 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 ; i<32 ; i++) { if (procarray[i].dwVMBase) { PROCESS *pp= procarray+i; list.resize(list.size()+1); CEPROCESSENTRY *cepe= &list.back(); //cepe->cntUsage= 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; }