/************************************************* ** FPSPSnoop ** ** print FPSP offending instructions out ** ** ** ** Version 40.3 © 30.08.2001 Thomas Richter ** ** THOR Software ** *************************************************/ /// Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// /// Defines #define LINE_F 0x2c #define OVERFLOW 0xd4 #define UNDERFLOW 0xcc #define SNAN 0xd8 #define OPERR 0xd0 #define BUN 0xc0 #define UNIMPDATA 0xdc #define INEX 0xc4 #define DIVZERO 0xc8 #define UNIMPEA 0xf0 #define UNIMPINT 0xf4 #define NONRESIDENT (MAPP_BLANK|MAPP_INVALID|MAPP_SWAPPED|MAPP_IO) #define TEMPLATE "NOFPSP/S,NOISP/S,NOOVL/S,NOUVL/S,NOSNAN/S,NOOPERR/S,NOBUN/S,NOINEX/S,NODIVZ/S,NOUNEA/S,NOUNDT/S" #define ARG_NOFPSP 0 #define ARG_NOISP 1 #define ARG_NOOVL 2 #define ARG_NOUVL 3 #define ARG_NOSNAN 4 #define ARG_NOOPERR 5 #define ARG_NOBUN 6 #define ARG_NOINEX 7 #define ARG_NODIVZ 8 #define ARG_NOUNEA 9 #define ARG_NOUNDT 10 #define ARG_NUM 11 /// /// Stuctures struct RegisterSet { ULONG rs_DataRegs[8]; APTR rs_AddrRegs[7]; APTR rs_USP; APTR rs_SSP; UWORD *rs_PC; UWORD rs_SR; UWORD rs_Vector; ULONG *rs_EA; extendedfloat rs_FPRegs[8]; ULONG rs_FPCR; APTR rs_FPIAR; ULONG rs_FPSR; }; /// /// Statics char version[]="$VER: FPSPSnoop 40.3 (30.8.2001) © THOR"; struct ExecBase *SysBase; struct DosLibrary *DOSBase; struct Library *UtilityBase; struct DisassemblerBase *DisassemblerBase; struct MMUBase *MMUBase; APTR OldVectors[0x100]; /// /// Externs extern APTR __asm *GetVBR(void); extern void __asm Exception_Callin(void); extern void __asm VPrintFmt(register __a0 char *fmtstring,register __a1 ULONG *stream,register __a6 struct ExecBase *SysBase); /// /// Protos LONG __saveds main(void); LONG InstallVecs(LONG *args); LONG RemoveVecs(void); void PrintFmt(char *fmtstring,...); void __asm __saveds Exception_Handler(register __a0 struct RegisterSet *); void __asm __saveds PutProc(register __d0 UBYTE c,register __a3 char **buf); void PrintFPU(extendedfloat x); BOOL IsValid(APTR addr); /// /// main LONG __saveds main(void) { LONG rc = 25; LONG args[ARG_NUM]; struct RDArgs *rd; SysBase = *(struct ExecBase **)(4L); memset(args,0,sizeof(args)); if (DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)) { if (UtilityBase = OpenLibrary("utility.library",37L)) { if (DisassemblerBase = (struct DisassemblerBase *)OpenLibrary("disassembler.library",40L)) { if (MMUBase = (struct MMUBase *)OpenLibrary("mmu.library",40L)) { if (rd = ReadArgs(TEMPLATE,args,NULL)) { rc = InstallVecs(args); if (rc == 0) { Wait(SIGBREAKF_CTRL_C); RemoveVecs(); } FreeArgs(rd); } else { PrintFault(IoErr(),"FPSPSnoop failed"); rc = 10; } CloseLibrary((struct Library *)MMUBase); } else { Printf("FPSPSnoop requires the mmu.library V40 or better.\n"); } CloseLibrary((struct Library *)DisassemblerBase); } else { Printf("FPSPSnoop requires the disassembler.library V40 or better.\n"); } CloseLibrary(UtilityBase); } CloseLibrary((struct Library *)DOSBase); } return rc; } /// /// InstallVecs LONG InstallVecs(LONG *args) { APTR *vbr; APTR exh = (APTR)(&Exception_Callin); Disable(); vbr = GetVBR(); memcpy(OldVectors,vbr,0x0100 * sizeof(ULONG)); if (!args[ARG_NOFPSP]) vbr[LINE_F>>2] = exh; if (!args[ARG_NOOVL]) vbr[OVERFLOW>>2]  = exh; if (!args[ARG_NOUVL]) vbr[UNDERFLOW>>2] = exh; if (!args[ARG_NOSNAN]) vbr[SNAN>>2] = exh; if (!args[ARG_NOOPERR]) vbr[OPERR>>2] = exh; if (!args[ARG_NOBUN]) vbr[BUN>>2] = exh; if (!args[ARG_NOUNDT]) vbr[UNIMPDATA>>2] = exh; if (!args[ARG_NOINEX]) vbr[INEX>>2] = exh; if (!args[ARG_NODIVZ]) vbr[DIVZERO>>2] = exh; if (!args[ARG_NOUNEA]) vbr[UNIMPEA>>2] = exh; if (!args[ARG_NOISP]) vbr[UNIMPINT>>2] = exh; Enable(); return 0; } /// /// RemoveVecs LONG RemoveVecs(void) { APTR *vbr; Disable(); vbr = GetVBR(); memcpy(vbr,OldVectors,0x100 * sizeof(ULONG)); Enable(); return 0; } /// /// PrintFmt void PrintFmt(char *fmtstring,...) { va_list args; va_start(args,fmtstring); VPrintFmt(fmtstring,(ULONG *)args,SysBase); va_end(args); } /// /// PutProc void __asm __saveds PutProc(register __d0 UBYTE c,register __a3 char **buf) { **buf = c; (*buf)++; **buf = 0; } /// /// Exception_Handler void __asm __saveds Exception_Handler(register __a0 struct RegisterSet *rs) { BOOL dumpfpu = TRUE; char sr[16],buffer[82],*bufptr; char *name; struct DisData ds; Disable(); PrintFmt("Caught 68040/68060 trap conditition: "); switch(rs->rs_Vector) { case LINE_F: PrintFmt("Unimplemented FPU instruction "); break; case OVERFLOW: PrintFmt("Overflow "); break; case UNDERFLOW: PrintFmt("Underflow "); break; case SNAN: PrintFmt("Signalling NAN "); break; case OPERR: PrintFmt("Operand Error "); break; case BUN: PrintFmt("Branch Unordered "); break; case UNIMPDATA: PrintFmt("Unimplemented FPU data type "); break; case INEX: PrintFmt("Inexact Result "); break; case DIVZERO: PrintFmt("FPU Divide by Zero "); break; case UNIMPEA: PrintFmt("Unimplemented EA "); break; case UNIMPINT: PrintFmt("Unimplemented integer instruction "); dumpfpu = FALSE; break; default: PrintFmt("Unexpected exception "); } PrintFmt("\n"); /* Fill in the SR */ sr[0] = (rs->rs_SR & 0x8000)?('T'):('_'); sr[1] = (rs->rs_SR & 0x4000)?('t'):('_'); sr[2] = (rs->rs_SR & 0x2000)?('S'):('_'); sr[3]  = (rs->rs_SR & 0x1000)?('M'):('_'); sr[4] = ((rs->rs_SR & 0x0700)>>8) | '0'; sr[5] = (rs->rs_SR & 0x10)?('X'):('_'); sr[6] = (rs->rs_SR & 0x08)?('N'):('_'); sr[7] = (rs->rs_SR & 0x04)?('Z'):('_'); sr[8]  = (rs->rs_SR & 0x02)?('V'):('_'); sr[9] = (rs->rs_SR & 0x01)?('C'):('_'); sr[10] = 0; if (rs->rs_SR & 0x0700) { name = "Autovector Interrupt"; } else { name = SysBase->ThisTask->tc_Node.ln_Name; if (!IsValid(name)) { name = "????"; } if (SysBase->ThisTask->tc_Node.ln_Type == NT_PROCESS) { struct Process *proc; proc = (struct Process *)(SysBase->ThisTask); if (proc->pr_CLI) { struct CommandLineInterface *cli; cli = (struct CommandLineInterface *)BADDR(proc->pr_CLI); if (IsValid(cli)) { if (cli->cli_CommandName) { char *modname; modname = (char *)BADDR(cli->cli_CommandName); if (IsValid(modname) && (*modname)) { name = modname+1; } } } } } } PrintFmt("PC : %x SR: %s USP: %x SSP: %x EA: %x (%c)(%c)\n" "Name : %s\n",rs->rs_PC,sr,rs->rs_USP,rs->rs_SSP,rs->rs_EA, (SysBase->IDNestCnt == -1)?(' '):('I'), (SysBase->TDNestCnt == -1)?(' '):('T'), name); PrintFmt("Data : %x %x %x %x %x %x %x %x\n", rs->rs_DataRegs[0],rs->rs_DataRegs[1],rs->rs_DataRegs[2],rs->rs_DataRegs[3], rs->rs_DataRegs[4],rs->rs_DataRegs[5],rs->rs_DataRegs[6],rs->rs_DataRegs[7]); PrintFmt("Addr : %x %x %x %x %x %x %x %x\n", rs->rs_AddrRegs[0],rs->rs_AddrRegs[1],rs->rs_AddrRegs[2],rs->rs_AddrRegs[3], rs->rs_AddrRegs[4],rs->rs_AddrRegs[5],rs->rs_AddrRegs[6], (rs->rs_SR & 0x2000)?(rs->rs_SSP):(rs->rs_USP)); if (rs->rs_EA) { if (IsValid(rs->rs_EA)) { PrintFmt("EA : %x %x %x %x %x %x %x %x\n", rs->rs_EA[0],rs->rs_EA[1],rs->rs_EA[2],rs->rs_EA[3], rs->rs_EA[4],rs->rs_EA[5],rs->rs_EA[6],rs->rs_EA[7]); } } if (dumpfpu) { int i; for (i = 0;i<8;i++) { PrintFmt("FP%c : ",i+'0'); PrintFPU((rs->rs_FPRegs[i])); } sr[0] = (rs->rs_FPCR & 0x8000)?('B'):('_'); sr[1] = (rs->rs_FPCR & 0x4000)?('S'):('_'); sr[2] = (rs->rs_FPCR & 0x2000)?('P'):('_'); sr[3] = (rs->rs_FPCR & 0x1000)?('O'):('_'); sr[4] = (rs->rs_FPCR & 0x0800)?('U'):('_'); sr[5] = (rs->rs_FPCR & 0x0400)?('D'):('_'); sr[6] = (rs->rs_FPCR & 0x0200)?('2'):('_'); sr[7] = (rs->rs_FPCR & 0x0100)?('1'):('_'); sr[8] = '.'; switch (rs->rs_FPCR & 0xc0) { case 0x00: sr[9] = 'n'; break; case 0x40: sr[9] = '0'; break; case 0x80: sr[9] = '-'; break; case 0xc0: sr[9] = '+'; break; } switch (rs->rs_FPCR & 0x30) { case 0x00: sr[10] = 'x'; break; case 0x10: sr[10] = 's'; break; case 0x20: sr[10] = 'd'; break; case 0x30: sr[10] = '?'; break; } sr[11] = 0; PrintFmt("FPCR : %s ",sr); sr[0] = (rs->rs_FPSR & (1<<27))?('N'):('_'); sr[1] = (rs->rs_FPSR & (1<<26))?('Z'):('_'); sr[2] = (rs->rs_FPSR & (1<<25))?('I'):('_'); sr[3] = (rs->rs_FPSR & (1<<24))?('U'):('_'); sr[4] = 0; PrintFmt("FPSR : %s.%c%x",sr,(rs->rs_FPSR & (1<<23))?('-'):('+'),(rs->rs_FPSR >> 16) & 0x7f); sr[0] = (rs->rs_FPSR & 0x8000)?('B'):('_'); sr[1] = (rs->rs_FPSR & 0x4000)?('S'):('_'); sr[2] = (rs->rs_FPSR & 0x2000)?('P'):('_'); sr[3] = (rs->rs_FPSR & 0x1000)?('O'):('_'); sr[4] = (rs->rs_FPSR & 0x0800)?('U'):('_'); sr[5] = (rs->rs_FPSR & 0x0400)?('D'):('_'); sr[6] = (rs->rs_FPSR & 0x0200)?('2'):('_'); sr[7] = (rs->rs_FPSR & 0x0100)?('1'):('_'); sr[8] = '.'; sr[9] = (rs->rs_FPSR & 0x80)?('v'):('_'); sr[10] = (rs->rs_FPSR & 0x40)?('o'):('_'); sr[11] = (rs->rs_FPSR & 0x20)?('u'):('_'); sr[12] = (rs->rs_FPSR & 0x10)?('d'):('_'); sr[13] = (rs->rs_FPSR & 0x08)?('i'):('_'); sr[14] = 0; PrintFmt(" %s FPIAR : %x\n\n",sr,rs->rs_FPIAR); } bufptr = buffer; ds.ds_From = rs->rs_PC; ds.ds_UpTo = rs->rs_PC+1; ds.ds_PC = rs->rs_PC; ds.ds_PutProc = (void *)(&PutProc); ds.ds_UserData = &bufptr; ds.ds_UserBase = NULL; ds.ds_Truncate = 80; ds.ds_reserved = 0; Disassemble(&ds); PrintFmt("%s\n",buffer); Enable(); } /// /// PrintFPU void PrintFPU(extendedfloat x) { char out[32]; XToA(x,out); PrintFmt("%x%x%x = %s\n",x[0],x[1],x[2],out); } /// /// IsValid BOOL IsValid(APTR addr) { struct MMUContext *ctx; ULONG prop; ctx = CurrentContext(NULL); ctx = SuperContext(ctx); prop = GetPageProperties(ctx,(ULONG)addr,TAG_DONE); if (prop & NONRESIDENT) return FALSE; prop = GetPageProperties(ctx,(ULONG)(addr) + 0x20,TAG_DONE); if (prop & NONRESIDENT) return FALSE; return TRUE; } ///