|
|
/****************************************************************************/ /* */ /* 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; i<len; i++) exeName[i] = exeName[i+delim]; exeName[len] = 0; return exeName+len; } /* GetModName */
/*--------------------------------------------------------------------------*/ /* */ /* FindSegSyms() - */ /* */ /*--------------------------------------------------------------------------*/
#ifdef WOW
int FindSegSyms(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD CSvalue); #pragma alloc_text(_MISCTEXT,FindSegSyms)
#endif
int FindSegSyms(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD CSvalue) { HANDLE hExe; struct new_exe far *pExe; struct new_seg1 far *pSeg; MAPDEF MapDef; MAPEND MapEnd; LPSTR pFileName; BYTE c; int i; int j; WORD seg_ptr;
if (lpRipInfo->symFH != -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); }
|