/****************************************************************************/ /* */ /* RIP.C - */ /* */ /* Debugging Support Routines */ /* */ /****************************************************************************/ #include "kernel.h" #include "newexe.h" #ifdef WOW // Note: The functions in this file were moved to the _MISCTEXT code segment // because _TEXT was exceeding the 64K segment limit a-craigj LPSTR htoa(LPSTR, WORD); LPSTR htoa0(LPSTR, WORD); LPSTR FAR far_htoa0(LPSTR, WORD); #pragma alloc_text(_MISCTEXT,far_htoa0) #pragma alloc_text(_MISCTEXT,htoa0) #pragma alloc_text(_MISCTEXT,htoa) #endif #if KDEBUG #include "logerror.h" #define API _far _pascal _loadds extern unsigned int DebugOptions; /* Defines for debug strings in STRINGS.ASM. */ #define DS_LOADFAIL 0 #define DS_NEWINSTLOADFAIL 1 #define DS_RESLOADERR 2 #define DS_CRLF 3 #define DS_FATALEXITCODE 4 #define DS_STACKOVERFLOW 5 #define DS_STACKTRACE 6 #define DS_ABORTBREAKIGNORE 7 #define DS_INVALIDBPCHAIN 8 #define DS_COLON 9 #define DS_REENTERFATALEXIT 10 #ifndef WOW LPSTR htoa(LPSTR, WORD); LPSTR htoa0(LPSTR, WORD); #endif char DebugRead(void); void DoAbort(void); void EnterBreak(int); HANDLE FAR GetExeHead(void); #ifdef WOW LONG NEAR PASCAL LSHL(WORD, int); #pragma alloc_text(_MISCTEXT,LSHL) int FAR DebugWrite(LPSTR, int); int FAR OpenSymFile(LPSTR); void FAR GetSymFileName(HANDLE, LPSTR); int FAR FarValidatePointer(LPSTR); BOOL FAR PASCAL IsCodeSelector(WORD); #else LONG PASCAL LSHL(WORD, int); int OpenSymFile(LPSTR); void GetSymFileName(HANDLE, LPSTR); int ValidatePointer(LPSTR); BOOL PASCAL IsCodeSelector(WORD); #endif WORD (far PASCAL *FatalExitProc)(WORD, WORD); int FAR FatalExitC(WORD); void FAR FatalAppExit(WORD, LPSTR); #ifdef WOW int FAR KernelError(int errCode, LPSTR lpmsg1, LPSTR lpmsg2); static char far *GetModName(char far *exeName); void API GetProcName(FARPROC lpfn, LPSTR lpch, int cch); WORD far *NextFrame(WORD far *lpFrame); void StackWalk(WORD arg); #pragma alloc_text(_MISCTEXT,KernelError) #pragma alloc_text(_MISCTEXT,GetModName) #pragma alloc_text(_MISCTEXT,GetProcName) #pragma alloc_text(_MISCTEXT,NextFrame) #pragma alloc_text(_MISCTEXT,StackWalk) #endif // WOW /* Debug Symbol Table Structures: * * For each symbol table (map): (MAPDEF) * ------------------------------------------------------------------------------------------------- * | map_ptr | lsa | pgm_ent | abs_cnt | abs_ptr | seg_cnt | seg_ptr | nam_max | nam_len | name... | * ------------------------------------------------------------------------------------------------- */ typedef struct tagMAPDEF { unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */ unsigned lsa ; /* 16 bit Load Segment address */ unsigned pgm_ent; /* 16 bit entry point segment value */ int abs_cnt; /* 16 bit count of constants in map */ unsigned abs_ptr; /* 16 bit ptr to constant chain */ int seg_cnt; /* 16 bit count of segments in map */ unsigned seg_ptr; /* 16 bit ptr to segment chain */ char nam_max; /* 8 bit Maximum Symbol name length */ char nam_len; /* 8 bit Symbol table name length */ } MAPDEF; typedef struct tagMAPEND { unsigned chnend; /* end of map chain (0) */ char rel; /* release */ char ver; /* version */ } MAPEND; /* For each segment/group within a symbol table: (SEGDEF) * -------------------------------------------------------------- * | nxt_seg | sym_cnt | sym_ptr | seg_lsa | name_len | name... | * -------------------------------------------------------------- */ typedef struct tagSEGDEF { unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */ int sym_cnt; /* 16 bit count of symbols in sym list */ unsigned sym_ptr; /* 16 bit ptr to symbol list */ unsigned seg_lsa; /* 16 bit Load Segment address */ unsigned seg_in0; /* 16 bit instance 0 physical address */ unsigned seg_in1; /* 16 bit instance 1 physical address */ unsigned seg_in2; /* 16 bit instance 2 physical address */ unsigned seg_in3; /* 16 bit instance 3 physical address */ unsigned seg_lin; /* 16 bit ptr to line number record */ char seg_ldd; /* 8 bit boolean 0 if seg not loaded */ char seg_cin; /* 8 bit current instance */ char nam_len; /* 8 bit Segment name length */ } SEGDEF; typedef SEGDEF FAR *LPSEGDEF; /* Followed by a list of SYMDEF's.. * for each symbol within a segment/group: (SYMDEF) * ------------------------------- * | sym_val | nam_len | name... | * ------------------------------- */ typedef struct tagSYMDEF { unsigned sym_val; /* 16 bit symbol addr or const */ char nam_len; /* 8 bit symbol name length */ } SYMDEF; typedef struct tagRIPINFO { char symName[128]; LPSTR pSymName; DWORD symFPos; int symFH; } RIPINFO; typedef RIPINFO FAR *LPRIPINFO; /*--------------------------------------------------------------------------*/ /* */ /* KernelError() - */ /* */ /*--------------------------------------------------------------------------*/ /* Print out the module name, the message which 'lpmsg1' points to, and the * value of 'lpmsg2' in hex. Then call FatalExit. */ int FAR KernelError(int errCode, LPSTR lpmsg1, LPSTR lpmsg2) { int n; char buf[16]; LPSTR pbuf; WORD hExe; WORD pfileinfo; struct new_exe far *pExe; /* Write out 'lpmsg1'. */ if (lpmsg1) DebugWrite(lpmsg1, 0); /* Is the second pointer non-NULL? */ if (lpmsg2) { /* Is the segment value non-NULL? */ if ( (hExe = (WORD)((DWORD)lpmsg2 >> 16)) #ifdef WOW && FarValidatePointer(lpmsg2) ) #else && ValidatePointer(lpmsg2) ) #endif { /* Does it point anywhere inside a New EXE Header? */ pExe = (struct new_exe far *)((DWORD)hExe << 16); if (pExe->ne_magic == NEMAGIC) { /* Write out the module name (1st in the resident names table).*/ pbuf = (LPSTR)(((DWORD)hExe << 16) | pExe->ne_restab); if (n = (int)((BYTE)*pbuf++)) { DebugWrite(pbuf, n); DebugWrite(GetDebugString(DS_COLON), 0); } /* Is the offset NULL? */ if (!LOWORD(lpmsg2)) { /* Get the pointer to the full-path name which we stuck in * the checksum a long time ago. */ if (pfileinfo = NE_PFILEINFO(*pExe)) (DWORD)lpmsg2 |= (DWORD)pfileinfo; else { pExe = (struct new_exe far *)((DWORD)GetExeHead() << 16); pfileinfo = NE_PFILEINFO(*pExe); lpmsg2 = (LPSTR)(((DWORD)hExe << 16) | pfileinfo); } lpmsg2 += 8; /* HERE???? */ } } /* Write out the full-path name. */ pbuf = lpmsg2; n = 0; while ((BYTE)*pbuf++ >= ' ') n++; if (n && n < 64) DebugWrite(lpmsg2, n); } /* Write out the second pointer in hex. */ pbuf = (LPSTR)buf; *pbuf++ = ' '; pbuf = htoa(pbuf, HIWORD(lpmsg2)); *pbuf++ = ':'; pbuf = htoa(pbuf, LOWORD(lpmsg2)); *pbuf++ = '\r'; *pbuf++ = '\n'; *pbuf++ = 0; DebugWrite((LPSTR)buf, 0); } /* Print errCode and dump the stack. */ return FatalExitC(errCode); } static char far *GetModName(char far *exeName) { int delim, dot, len, i; delim = 0; dot = 0; for (i=0; i<80 && exeName[i]; i++) { if (exeName[i] == '.') dot = i; if (exeName[i] == ':' || exeName[i] == '\\') delim = i+1; } if (!dot) dot = i; len = dot - delim; for (i=0; isymFH != -1) { _lclose(lpRipInfo->symFH); lpRipInfo->symFH = -1; } hExe = GetExeHead(); while (hExe) { pExe = (struct new_exe far *)((DWORD)hExe << 16); pSeg = (struct new_seg1 far *)(((DWORD)hExe << 16) | pExe->ne_segtab); for (i=0; i < pExe->ne_cseg; i++, pSeg++) { #if 1 if (HIWORD(GlobalHandleNoRIP((HANDLE)pSeg->ns_handle)) == CSvalue) #else if (MyLock((HANDLE)pSeg->ns_handle) == CSvalue) #endif { lpRipInfo->pSymName = (LPSTR)lpRipInfo->symName; GetSymFileName(hExe, lpRipInfo->pSymName); if ((lpRipInfo->symFH = OpenSymFile(lpRipInfo->pSymName)) != -1) { _lread(lpRipInfo->symFH, (LPSTR)&MapDef, sizeof(MAPDEF)); _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)MapDef.nam_len)); if (i > MapDef.seg_cnt) /* Too much assembly */ goto ModName; lpRipInfo->pSymName += MapDef.nam_len; *lpRipInfo->pSymName++ = '!'; *lpRipInfo->pSymName = 0; seg_ptr = (WORD)MapDef.seg_ptr; _llseek(lpRipInfo->symFH, -(long)sizeof(MAPEND), 2); _lread(lpRipInfo->symFH, (LPSTR)&MapEnd, sizeof(MAPEND)); if (MapEnd.ver != 3) goto ModName; j = i + 1; while (j--) { if (MapEnd.rel >= 10) _llseek(lpRipInfo->symFH, LSHL(seg_ptr, 4), 0); else _llseek(lpRipInfo->symFH, (long)seg_ptr, 0); _lread( lpRipInfo->symFH, (LPSTR)lpSegDef, sizeof(*lpSegDef)); seg_ptr = (WORD)lpSegDef->nxt_seg; } _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)lpSegDef->nam_len)); lpRipInfo->pSymName += lpSegDef->nam_len; *lpRipInfo->pSymName++ = ':'; *lpRipInfo->pSymName = 0; lpRipInfo->symFPos = (DWORD)_llseek(lpRipInfo->symFH, 0L, 1); return(TRUE); } /* if opened file */ ModName: /* Put Module on line: USER(0033)XXXX:XXXX */ GetSymFileName(hExe, lpRipInfo->symName); lpRipInfo->pSymName = GetModName(lpRipInfo->symName); *lpRipInfo->pSymName++ = '('; lpRipInfo->pSymName = htoa0(lpRipInfo->pSymName, i+1); *lpRipInfo->pSymName++ = ')'; *lpRipInfo->pSymName = 0; goto TermName; } } hExe = (HANDLE)NE_PNEXTEXE(*pExe); } lpRipInfo->pSymName = lpRipInfo->symName; TermName: /* Add segment:offset to line */ lpRipInfo->pSymName = htoa((LPSTR)lpRipInfo->pSymName, CSvalue); *lpRipInfo->pSymName++ = ':'; *lpRipInfo->pSymName = 0; if (lpRipInfo->symFH != -1) { _lclose(lpRipInfo->symFH); lpRipInfo->symFH = -1; } return(FALSE); } /*--------------------------------------------------------------------------*/ /* */ /* FindSymbol() - */ /* */ /*--------------------------------------------------------------------------*/ #ifdef WOW int FindSymbol(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD offset); #pragma alloc_text(_MISCTEXT,FindSymbol) #endif int FindSymbol(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD offset) { WORD i; DWORD symPos, curPos; LPSTR s; SYMDEF SymDef; if (lpRipInfo->symFH != -1) { curPos = symPos = (DWORD)_llseek(lpRipInfo->symFH, (long)lpRipInfo->symFPos, 0); i = (WORD)lpSegDef->sym_cnt; while (i--) { _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF)); if ((WORD)SymDef.sym_val > offset) break; symPos = curPos; curPos = _llseek(lpRipInfo->symFH, (long)SymDef.nam_len, 1); } _llseek(lpRipInfo->symFH, (long)symPos, 0); _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF)); s = lpRipInfo->pSymName; _lread(lpRipInfo->symFH, s, (int)((BYTE)SymDef.nam_len)); s += SymDef.nam_len; if ((WORD)SymDef.sym_val < offset) { *s++ = '+'; s = htoa0(s, offset - SymDef.sym_val); } *s = 0; return(TRUE); } s = htoa(lpRipInfo->pSymName, offset); *s = 0; return(FALSE); } void API GetProcName(FARPROC lpfn, LPSTR lpch, int cch) { RIPINFO RipInfo; SEGDEF SegDef; static char lastName[128] = "test"; static FARPROC lastfn = 0; if (lastfn == lpfn) { /* cache last symbol name looked up */ lstrcpy(RipInfo.symName, lastName); } else { RipInfo.pSymName = 0L; RipInfo.symFH = -1; FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, HIWORD(lpfn)); FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, LOWORD(lpfn)); if (RipInfo.symFH != -1) { _lclose(RipInfo.symFH); RipInfo.symFH = -1; } lstrcpy(lastName, RipInfo.symName); lastfn = lpfn; } if (cch > 1) { if (cch > sizeof(RipInfo.symName)) cch = sizeof(RipInfo.symName); RipInfo.symName[cch-1] = 0; lstrcpy(lpch, RipInfo.symName); } } /*--------------------------------------------------------------------------*/ /* */ /* NextFrame() - */ /* */ /*--------------------------------------------------------------------------*/ WORD far *NextFrame(WORD far *lpFrame) { WORD w; /* Force BP even. */ w = *lpFrame & 0xFFFE; /* Are we at the end of the BP chain? */ if (w) { /* BPs should decrease as we move down the chain. */ if (w <= LOWORD(lpFrame)) goto BadBP; /* Are we above the top of the stack (SS:000A contains pStackTop)? */ lpFrame = (WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | 0x0A); if (w < *lpFrame++) goto BadBP; /* Are we below the bottom of the stack (SS:000C contains pStackMin)? */ if (w > *++lpFrame) goto BadBP; /* Return the address of the next BP. */ return((WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | w)); } else return((WORD far *)0L); BadBP: DebugWrite(GetDebugString(DS_INVALIDBPCHAIN), 0); return((WORD far *)0L); } /*--------------------------------------------------------------------------*/ /* */ /* StackWalk() - */ /* */ /*--------------------------------------------------------------------------*/ void StackWalk(WORD arg) { /* WORD arg; /* NOTE: 'arg' is only used as a pointer into the frame. */ /* If we subtract 2 words from 'arg's location, we */ /* get the address of the previous frame's BP!!! */ WORD far *lpFrame; WORD wCurBP; WORD wCurRetOffset; WORD curCS; RIPINFO RipInfo; SEGDEF SegDef; RipInfo.pSymName = 0L; RipInfo.symFH = -1; /* Have 'lpFrame' point to the previous frame's BP. */ lpFrame = &arg - 2; curCS = 0; while (lpFrame = NextFrame(lpFrame)) { /* Get the next BP. Stop if it is zero. */ wCurBP = *lpFrame; if (!wCurBP) break; /* Get the current frame's return address offset. */ wCurRetOffset = lpFrame[1]; /* Have we changed code segments (Far call && Different CS)? */ if (((wCurBP & 1) || IsCodeSelector(lpFrame[2])) && (curCS != lpFrame[2])) { /* Yes, get the new segment's name. */ curCS = lpFrame[2]; FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, curCS); } /* Move back to the address of the actual call instruction. */ if ((wCurBP & 1) || IsCodeSelector(lpFrame[2])) /* Near or Far call? */ wCurRetOffset -= 5; else wCurRetOffset -= 3; FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, wCurRetOffset); DebugWrite((LPSTR)RipInfo.symName, 0); DebugWrite(GetDebugString(DS_CRLF), 0); } if (RipInfo.symFH != -1) _lclose(RipInfo.symFH); } #ifndef WOW /*--------------------------------------------------------------------------*/ /* */ /* FatalExit() - */ /* */ /*--------------------------------------------------------------------------*/ /* Debugging version. Retail version in RIPAUX.ASM. */ /* Kernel DS setup by prolog code */ int FAR FatalExitC(WORD errCode) { /* return 1 to break execution */ char c; char buf[7]; LPSTR pbuf; int rep=0; /* This calls the TOOLHELP RIP hook */ if ( FatalExitProc ) { _asm { push errCode push bp call DWORD PTR FatalExitProc or ax,ax jz NoReturn } return 0; _asm NoReturn:; } #if 0 static BOOL fInsideFatalExit = FALSE; if (fInsideFatalExit) { DebugWrite(GetDebugString(DS_REENTERFATALEXIT), 0); return 0; } fInsideFatalExit = TRUE; #endif ReRip: /* Display "FatalExit Code =" */ DebugWrite(GetDebugString(DS_FATALEXITCODE), 0); /* Did the stack overflow? */ if (errCode == -1) DebugWrite(GetDebugString(DS_STACKOVERFLOW), 0); else { /* Display the error code in hex. */ pbuf = (LPSTR)buf; *pbuf++ = '0'; *pbuf++ = 'x'; pbuf = htoa(pbuf, (WORD)errCode); *pbuf++ = 0; DebugWrite((LPSTR)buf, 0); } /* Display the Stack Trace. */ if (rep /* || (DebugOptions & DBO_RIP_STACK) */) { DebugWrite(GetDebugString(DS_STACKTRACE), 0); StackWalk(0); } while (TRUE) { /* Display "Abort, Break, Ignore" */ DebugWrite(GetDebugString(DS_ABORTBREAKIGNORE), 0); /* Get and process the user's response. */ c = DebugRead(); DebugWrite(GetDebugString(DS_CRLF), 0); if (c >= 'a' && c <= 'z') c += 'A' - 'a'; switch (c) { case 'A': DoAbort(); case 'B': /* fInsideFatalExit = FALSE; */ /* EnterBreak(2); */ return 1; case 0 : case 'I': /* fInsideFatalExit = FALSE; */ return 0; case 'X': case 'E': FatalAppExit(0, "Terminating Application"); break; case ' ': case 13: rep = 1; goto ReRip; default: ; } } } #endif // ifndef WOW #endif // if KDEBUG /*--------------------------------------------------------------------------*/ /* */ /* htoa() - */ /* */ /*--------------------------------------------------------------------------*/ /* Converts 'w' into a hex string in 's'. */ LPSTR htoa(s, w) LPSTR s; WORD w; { int i; char c; i = 4; s += i; while (i--) { c = (char)(w & (WORD)0x000F); w >>= 4; if (c > 9) c += 'A' - 10; else c += '0'; *--s = c; } return(s+4); } /* skip leading 0's */ LPSTR htoa0(LPSTR s, WORD w) { int i; char c; int flag = 0; i = 4; while (i--) { c = (char)((w>>12) & (WORD)0x000F); w <<= 4; if (c > 9) c += 'A' - 10; else c += '0'; if (c > '0' || flag || !i) { *s++ = c; flag = 1; } } return s; } LPSTR FAR far_htoa0( LPSTR s, WORD w) { return htoa0( s, w); }