PSHORT AllineaCh (PSHORT pCh, ULONG nByte, ULONG func) { PBYTE pCh8 = NULL; ULONG pflag; ULONG psize; LONG p; APIRET rc; psize = (ULONG) &nByte; pflag = PAG_READ | PAG_WRITE | PAG_COMMIT; rc = DosQueryMem (pCh, &psize, &pflag); if (rc) { switch (rc) { case NO_ERROR: break; case ERROR_INVALID_ADDRESS: SendMsg (func, ERR_TRACCIA_ERRATA); return 0; break; default: printf (" DosQueryMem rc:%i\n", rc); return 0; break; } } p = (long) pCh *2; pCh = pCh + (nByte * 2) - 2; psize = (ULONG) &nByte; rc = DosQueryMem (pCh, &psize, &pflag); if (rc) { switch (rc) { case NO_ERROR: break; case ERROR_INVALID_ADDRESS: SendMsg (func, ERR_TRACCIA_INSUFFICIENTE); return 0; break; default: printf (" DosQueryMem rc:%i\n", rc); return 0; break; } } return (PSHORT) p; }
/* * Touches (reads/writes) the first word in every page of memory pointed to by * buf of len bytes. If buf is not on the page boundary, the word at buf is * touched instead. Note that the page is only touched if it's reserved (i.e. * neither committed, nor free). * * This function is used to work around a bug in DosRead that causes it to fail * when interrupted by the exception handler, see * https://github.com/bitwiseworks/libcx/issues/21. */ void touch_pages(void *buf, size_t len) { APIRET arc; ULONG dos_len; ULONG dos_flags; volatile ULONG buf_addr = (ULONG)buf; ULONG buf_end = buf_addr + len; /* * Note: we need to at least perform the write operation when toucing so that * in case if it's our memory mapped region then it's marked dirty and with * PAG_WRITE is set (on read PAG_WRITE would have been removed whcih would * cause DosRead to fail too). And, to make sure that the touched region is * not corrupted by touching, we first read the target word and then simply * write it back. */ if (!PAGE_ALIGNED(buf_addr)) { dos_len = PAGE_SIZE; arc = DosQueryMem((PVOID)PAGE_ALIGN(buf_addr), &dos_len, &dos_flags); TRACE_IF(arc, "DosQueryMem = %lu\n", arc); if (!arc && !(dos_flags & (PAG_FREE | PAG_COMMIT))) *(int *)buf_addr = *(int *)buf_addr; buf_addr = PAGE_ALIGN(buf_addr) + PAGE_SIZE; } while (buf_addr < buf_end) { dos_len = ~0U; arc = DosQueryMem((PVOID)PAGE_ALIGN(buf_addr), &dos_len, &dos_flags); TRACE_IF(arc, "DosQueryMem = %lu\n", arc); if (!arc && !(dos_flags & (PAG_FREE | PAG_COMMIT))) { /* touch all pages within the reported range */ dos_len += buf_addr; while (buf_addr < dos_len) { *(int *)buf_addr = *(int *)buf_addr; buf_addr += PAGE_SIZE; } } else { buf_addr += dos_len; } } }
VOID excDescribePage(FILE *file, ULONG ulCheck) { APIRET arc; ULONG ulCountPages = 1; ULONG ulFlagsPage = 0; arc = DosQueryMem((PVOID)ulCheck, &ulCountPages, &ulFlagsPage); if (arc == NO_ERROR) { fprintf(file, "valid, flags: "); if (ulFlagsPage & PAG_READ) fprintf(file, "read "); if (ulFlagsPage & PAG_WRITE) fprintf(file, "write "); if (ulFlagsPage & PAG_EXECUTE) fprintf(file, "execute "); if (ulFlagsPage & PAG_GUARD) fprintf(file, "guard "); if (ulFlagsPage & PAG_COMMIT) fprintf(file, "committed "); if (ulFlagsPage & PAG_SHARED) fprintf(file, "shared "); if (ulFlagsPage & PAG_FREE) fprintf(file, "free "); if (ulFlagsPage & PAG_BASE) fprintf(file, "base "); } else if (arc == ERROR_INVALID_ADDRESS) fprintf(file, "invalid"); }
ULONG APIENTRY FileExceptionHandler( PEXCEPTIONREPORTRECORD pReport, struct _EXCEPTIONREGISTRATIONRECORD * pXReg, PCONTEXTRECORD pContext, PVOID pDispatch) { CAMJXRR * pReg = (CAMJXRR*)pXReg; ULONG ulRtn = XCPT_CONTINUE_SEARCH; ULONG rc = 0; ULONG ulSize; ULONG ulAttr; LONG lOffs; char * pErr = 0; PVOID pMem; do { if (pReport->fHandlerFlags || pReport->ExceptionNum != XCPT_ACCESS_VIOLATION || pReport->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN || pReport->ExceptionInfo[0] != XCPT_READ_ACCESS || pReport->ExceptionInfo[1] == XCPT_DATA_UNKNOWN || pReport->ExceptionInfo[1] < (ULONG)pReg->pBase || pReport->ExceptionInfo[1] >= (ULONG)pReg->pEnd) { printf( "*** Exception not handled - %08lx\n", pReport->ExceptionNum); return (ulRtn); } if (pReg->lFilePtr >= pReg->lEOF) ERRMSG( "already at EOF") pMem = (PVOID)(pReport->ExceptionInfo[1] & ~0xFFF); ulSize = 1; ulAttr = 0; rc = DosQueryMem( pMem, &ulSize, &ulAttr); if (rc) ERRMSG( "DosQueryMem") if (ulAttr & (PAG_FREE | PAG_COMMIT)) { rc = ulAttr; ERRMSG( "unexpected memory attributes") } rc = DosSetMem( pMem, 0x1000, PAG_COMMIT | PAG_DEFAULT); if (rc) ERRMSG( "DosSetMem") lOffs = (BYTE*)pMem - pReg->pBase; if (lOffs != pReg->lFilePtr) { rc = DosSetFilePtr( pReg->hFile, lOffs, FILE_BEGIN, &pReg->lFilePtr); if (rc) ERRMSG( "DosSetFilePtr") if (lOffs != pReg->lFilePtr) { rc = lOffs; ERRMSG( "seek beyond EOF") }
/* to by the first entry point in a module */ void ForceModuleLoad(HMODULE hmodule) { /* DosQueryMem */ unsigned long memsize=0; unsigned long memend=0; unsigned long memflags=0; /* DosQueryProcAddr */ PFN modaddr; volatile unsigned char cpybuf; unsigned int base=0; unsigned char* baseptr=0; if (DosQueryProcAddr(hmodule,1,0,&modaddr) == NO_ERROR) { /* calc 64K aligned addr previous to entry point */ base=(( (unsigned long)modaddr) & 0xFFFF0000); /* get size and flags for this memory area */ memsize=0x0fffffff; DosQueryMem((void*)base,&memsize,&memflags); /* if not first page of object, back off addr and retry */ while (memflags < PAG_BASE) { base=base - PAG_BASE; memsize=0x0fffffff; DosQueryMem((void*)base,&memsize,&memflags); } /* finally, now loop through object pages, force page-in */ memend=base+memsize; while(base<memend) { baseptr=(unsigned char*)base; cpybuf=*baseptr; base+=4096; } } }
static void UnmapPages(void *addr, size_t size) { if (!DosFreeMem(addr)) return; /* if DosFreeMem() failed, 'addr' is probably part of an "expensive" * allocation, so calculate the base address and try again */ unsigned long cb = 2 * size; unsigned long flags; if (DosQueryMem(addr, &cb, &flags) || cb < size) return; jsuword base = reinterpret_cast<jsuword>(addr) - ((2 * size) - cb); DosFreeMem(reinterpret_cast<void*>(base)); return; }
static void * MapAlignedPagesRecursively(size_t size, size_t alignment, int& recursions) { if (++recursions >= OS2_MAX_RECURSIONS) return NULL; void *tmp; if (DosAllocMem(&tmp, size, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) { JS_ALWAYS_TRUE(DosAllocMem(&tmp, size, PAG_COMMIT | PAG_READ | PAG_WRITE) == 0); } size_t offset = reinterpret_cast<jsuword>(tmp) & (alignment - 1); if (!offset) return tmp; /* if there are 'filler' bytes of free space above 'tmp', free 'tmp', * then reallocate it as a 'filler'-sized block; assuming we're not * in a race with another thread, the next recursion should succeed */ size_t filler = size + alignment - offset; unsigned long cb = filler; unsigned long flags = 0; unsigned long rc = DosQueryMem(&(static_cast<char*>(tmp))[size], &cb, &flags); if (!rc && (flags & PAG_FREE) && cb >= filler) { UnmapPages(tmp, 0); if (DosAllocMem(&tmp, filler, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) { JS_ALWAYS_TRUE(DosAllocMem(&tmp, filler, PAG_COMMIT | PAG_READ | PAG_WRITE) == 0); } } void *p = MapAlignedPagesRecursively(size, alignment, recursions); UnmapPages(tmp, 0); return p; }
/* * Exception handler; attempt to commit memory if access violation occures. */ static ULONG _System exception_handler(PEXCEPTIONREPORTRECORD pERepRec, PEXCEPTIONREGISTRATIONRECORD pERegRep, PCONTEXTRECORD pCtxRec, PVOID p) { ULONG ulRet = XCPT_CONTINUE_EXECUTION; switch(pERepRec->ExceptionNum) { case XCPT_ACCESS_VIOLATION: ulRet = XCPT_CONTINUE_SEARCH; if(pERepRec->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN) { } else { APIRET rc = NO_ERROR; ULONG cbMem = 1; ULONG flMem = 0; rc = DosQueryMem((PVOID)pERepRec->ExceptionInfo[1], &cbMem, &flMem); if((flMem & PAG_FREE) == 0) { rc = DosSetMem((PVOID)pERepRec->ExceptionInfo[1], 4096, PAG_DEFAULT | PAG_COMMIT); if(rc == NO_ERROR) { ulRet = XCPT_CONTINUE_EXECUTION; } } } break; default: ulRet = XCPT_CONTINUE_SEARCH; break; } return ulRet; }
APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) { ULONG flags, size = 0x1000000; DosQueryMem(m->memblock, &size, &flags); return size; }
VOID excExplainException(FILE *file, // in: logfile from fopen() PSZ pszHandlerName, // in: descriptive string PEXCEPTIONREPORTRECORD pReportRec, // in: excpt info PCONTEXTRECORD pContextRec) // in: excpt info { PTIB ptib = NULL; PPIB ppib = NULL; HMODULE hMod1, hMod2; CHAR szMod1[CCHMAXPATH] = "unknown", szMod2[CCHMAXPATH] = "unknown"; ULONG ulObjNum, ulOffset, ulCountPages, ulFlagsPage; APIRET arc; PULONG pulStackWord, pulStackBegin; ULONG ul; ULONG ulOldPriority = 0x0100; // regular, delta 0 // raise this thread's priority, because this // might take some time if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR) if (ptib) if (ptib->tib_ptib2) { ulOldPriority = ptib->tib_ptib2->tib2_ulpri; DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0); // current thread } // make some noise DosBeep(4000, 30); DosBeep(2000, 30); DosBeep(1000, 30); DosBeep( 500, 30); DosBeep( 250, 30); DosBeep( 500, 30); DosBeep(1000, 30); DosBeep(2000, 30); DosBeep(4000, 30); // generic exception info fprintf(file, "\n%s:\n Exception type: %08X\n Address: %08X\n Params: ", pszHandlerName, pReportRec->ExceptionNum, pReportRec->ExceptionAddress); for (ul = 0; ul < pReportRec->cParameters; ul++) { fprintf(file, "%08X ", pReportRec->ExceptionInfo[ul]); } // now explain the exception in a bit more detail; // depending on the exception, pReportRec->ExceptionInfo // contains some useful data switch (pReportRec->ExceptionNum) { case XCPT_ACCESS_VIOLATION: { fprintf(file, "\nAccess violation: "); if (pReportRec->ExceptionInfo[0] & XCPT_READ_ACCESS) fprintf(file, "Invalid read access from 0x%04X:%08X.\n", pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); else if (pReportRec->ExceptionInfo[0] & XCPT_WRITE_ACCESS) fprintf(file, "Invalid write access to 0x%04X:%08X.\n", pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); else if (pReportRec->ExceptionInfo[0] & XCPT_SPACE_ACCESS) fprintf(file, "Invalid space access at 0x%04X.\n", pReportRec->ExceptionInfo[1]); else if (pReportRec->ExceptionInfo[0] & XCPT_LIMIT_ACCESS) fprintf(file, "Invalid limit access occurred.\n"); else if (pReportRec->ExceptionInfo[0] == XCPT_UNKNOWN_ACCESS) fprintf(file, "unknown at 0x%04X:%08X\n", pContextRec->ctx_SegDs, pReportRec->ExceptionInfo[1]); fprintf(file, "Explanation: An attempt was made to access a memory object which does\n" " not belong to the current process. Most probable causes\n" " for this are that an invalid pointer was used, there was\n" " confusion with administering memory or error conditions \n" " were not properly checked for.\n"); break; } case XCPT_INTEGER_DIVIDE_BY_ZERO: { fprintf(file, "\nInteger division by zero.\n"); fprintf(file, "Explanation: An attempt was made to divide an integer value by zero,\n" " which is not defined.\n"); break; } case XCPT_ILLEGAL_INSTRUCTION: { fprintf(file, "\nIllegal instruction found.\n"); fprintf(file, "Explanation: An attempt was made to execute an instruction that\n" " is not defined on this machine's architecture.\n"); break; } case XCPT_PRIVILEGED_INSTRUCTION: { fprintf(file, "\nPrivileged instruction found.\n"); fprintf(file, "Explanation: An attempt was made to execute an instruction that\n" " is not permitted in the current machine mode or that\n" " XFolder had no permission to execute.\n"); break; } case XCPT_INTEGER_OVERFLOW: fprintf(file, "\nInteger overflow.\n"); fprintf(file, "Explanation: An integer operation generated a carry-out of the most\n" " significant bit. This is a sign of an attempt to store\n" " a value which does not fit into an integer variable.\n"); } if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR) { /* * process info: * */ if (ppib) { if (pContextRec->ContextFlags & CONTEXT_CONTROL) { // get the main module hMod1 = ppib->pib_hmte; DosQueryModuleName(hMod1, sizeof(szMod1), szMod1); // get the trapping module DosQueryModFromEIP(&hMod2, &ulObjNum, sizeof(szMod2), szMod2, &ulOffset, pContextRec->ctx_RegEip); DosQueryModuleName(hMod2, sizeof(szMod2), szMod2); } fprintf(file, "\nProcess information: PID 0x%lX" "\n Module handle: 0x%lX (%s)" "\n Trapping module: 0x%lX (%s)" "\n Object: %d\n", ppib->pib_ulpid, hMod1, szMod1, hMod2, szMod2, ulObjNum); } else fprintf(file, "\nProcess information was not available."); // *** registers fprintf(file, "\nRegisters:"); if (pContextRec->ContextFlags & CONTEXT_INTEGER) { // EAX fprintf(file, "\n EAX = %08X ", pContextRec->ctx_RegEax); excDescribePage(file, pContextRec->ctx_RegEax); // EBX fprintf(file, "\n EBX = %08X ", pContextRec->ctx_RegEbx); excDescribePage(file, pContextRec->ctx_RegEbx); // ECX fprintf(file, "\n ECX = %08X ", pContextRec->ctx_RegEcx); excDescribePage(file, pContextRec->ctx_RegEcx); // EDX fprintf(file, "\n EDX = %08X ", pContextRec->ctx_RegEdx); excDescribePage(file, pContextRec->ctx_RegEdx); // ESI fprintf(file, "\n ESI = %08X ", pContextRec->ctx_RegEsi); excDescribePage(file, pContextRec->ctx_RegEsi); // EDI fprintf(file, "\n EDI = %08X ", pContextRec->ctx_RegEdi); excDescribePage(file, pContextRec->ctx_RegEdi); fprintf(file, "\n"); } else fprintf(file, " not available\n"); if (pContextRec->ContextFlags & CONTEXT_CONTROL) { // *** instruction fprintf(file, "Instruction:\n CS:EIP = %04X:%08X ", pContextRec->ctx_SegCs, pContextRec->ctx_RegEip); excDescribePage(file, pContextRec->ctx_RegEip); // *** CPU flags fprintf(file, "\n FLG = %08X", pContextRec->ctx_EFlags); /* * stack: * */ fprintf(file, "\nStack:\n Base: %08X\n Limit: %08X", (ptib ? ptib->tib_pstack : 0), (ptib ? ptib->tib_pstacklimit :0)); fprintf(file, "\n SS:ESP = %04X:%08X ", pContextRec->ctx_SegSs, pContextRec->ctx_RegEsp); excDescribePage(file, pContextRec->ctx_RegEsp); fprintf(file, "\n EBP = %08X ", pContextRec->ctx_RegEbp); excDescribePage(file, pContextRec->ctx_RegEbp); dbgPrintStack(file, (PUSHORT)ptib->tib_pstack, (PUSHORT)ptib->tib_pstacklimit, (PUSHORT)pContextRec->ctx_RegEbp, (PUSHORT)pReportRec->ExceptionAddress); /* * stack dump: * this code is mostly (W) Roman Stangl. */ if (ptib != 0) { #ifdef DEBUG_EXCPT_STACKDUMP // start with Stack dump; if EBP is within stack and smaller // than ESP, use EBP, otherwise use ESP (which points into the // stack anyway, so no check needed) fprintf(file, "\n\nStack dump : +0 +4 +8 +C"); if (pContextRec->ctx_RegEbp < pContextRec->ctx_RegEsp) pulStackWord = (PULONG)(pContextRec->ctx_RegEbp & 0xFFFFFFF0); else pulStackWord = (PULONG)(pContextRec->ctx_RegEsp & 0xFFFFFFF0); for (pulStackBegin = pulStackWord; pulStackWord <= (PULONG)ptib->tib_pstacklimit; /* NOP */) { if (((ULONG)pulStackWord & 0x00000FFF) == 0x00000000) { // we're on a page boundary: check access ulCountPages = 0x1000; ulFlagsPage = 0; arc = DosQueryMem((void *)pulStackWord, &ulCountPages, &ulFlagsPage); if ( (arc != NO_ERROR) || ( (arc == NO_ERROR) && ( !( ((ulFlagsPage & (PAG_COMMIT|PAG_READ)) == (PAG_COMMIT|PAG_READ)) ) ) ) ) { fprintf(file, "\n %08X: ", pulStackWord); fprintf(file, "Page inaccessible"); pulStackWord += 0x1000; continue; // for } } if (((ULONG)pulStackWord & 0x0000000F) == 0) fprintf(file, "\n %08X: ", pulStackWord); if ( (*pulStackWord >= (ULONG)pulStackBegin) && (*pulStackWord <= (ULONG)ptib->tib_pstacklimit) ) fprintf(file, "<%08X> ", *pulStackWord); else fprintf(file, " %08X ", *pulStackWord); pulStackWord++; } // end for #endif // *** stack frames fprintf(file, "\n\nStack frames:\n Address Module:Object\n"); pulStackWord = (PULONG)pContextRec->ctx_RegEbp; while ( (pulStackWord != 0) && (pulStackWord < (PULONG)ptib->tib_pstacklimit) ) { fprintf(file, " %08X: %08X ", pulStackWord, *(pulStackWord+1)); if (DosQueryModFromEIP(&hMod1, &ulObjNum, sizeof(szMod1), szMod1, &ulOffset, *(pulStackWord+1)) == NO_ERROR) { fprintf(file, " %s:%d\n", szMod1, ulObjNum); } pulStackWord = (PULONG)*(pulStackWord); } // end while } } } fprintf(file, "\n"); // reset old priority DosSetPriority(PRTYS_THREAD, (ulOldPriority & 0x0F00) >> 8, (UCHAR)ulOldPriority, 0); // current thread }