/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by Mike Parker.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include "../sys/rciext/kacrash.h"

crashMessage (s, cp, onunix)
char *s;
register CRASHINFO *cp;
int onunix;
{
	int k, j;

	/* This routine analyses the crash information provided in the
	   indicated CRASHINFO structure and provides a formatted
	   message indiacting the nature of the crash (i.e., 'integer
	   divide by zero', or 'access violation'), as well as useful
	   information like the program counter where the crash occurred,
	   the address in the case of memory access faults, etc.

	   The crash information itself is returned by the ka driver (for
	   task running on the auxiliary processors), or by an RCI
	   device driver (for task executing on the arbiter).
	*/
	
	switch (cp->type)
	 { default:
	    { sprintf (s,
	      "ERROR -- bogus crash type specified (%d)", cp->type);
	      break;
	    }
	   case CI_NULL:
	    { sprintf (s,
	      "no exit type specified");
	      break;
	    }
	   case CI_EXIT:
	    { if (onunix)
	       { sprintf (s,
		 "ERROR -- crash type EXIT shouldn't be set on UNIX");
	       }
	      else
	       { sprintf (s,
		 "program exited with code %d", cp->u.subtype);
		 break;
	       }
	    }
	   case CI_ARITHTRAP:	/* kill with SIGFPE */
	    { char *subtype = 0;

	      switch (cp->u.subtype)
	       {
		 case (CI_AT_IOVERF): /* integer overflow */
		  { subtype = "integer overflow trap";
		    break;
		  }
		 case (CI_AT_IDIVZ): /* integer divide-by-zero */
		  { subtype = "integer divide by zero trap";
		    break;
		  }
		 case (CI_AT_FOVERF): /* floating overflow */
		  { subtype = "floating overflow trap";
		    break;
		  }
		 case (CI_AT_FDIVZ): /* floating divide-by-zero */
		  { subtype = "floating divide by zero trap";
		    break;
		  }
		 case (CI_AT_FUNDERF): /* floating underflow */
		  { subtype = "floating underflow trap";
		    break;
		  }
		 case (CI_AT_DOVERF): /* decimal overflow */
		  { subtype = "decimal overflow trap";
		    break;
		  }
		 case (CI_AT_SUBRANGE): /* subscript range */
		  { subtype = "subscript out of range trap";
		    break;
		  }
		 case (CI_AF_FOVERF): /* floating overflow */
		  { subtype = "floating overflow fault";
		    break;
		  }
		 case (CI_AF_FDIVZ): /* floating divide-by-zero */
		  { subtype = "floating divide by zero fault";
		    break;
		  }
		 case (CI_AF_FUNDERF):
		  { subtype = "floating underflow fault";
		    break;
		  }
	       }
	      if (subtype)
	       { sprintf (s, "arithmetic trap, pc = 0x%x (%s)", 
			  cp->pc, subtype);
	       }
	      else
	       { sprintf (s, "arithmetic trap, pc = 0x%x (%s %d)", 
			  cp->pc, "ERROR -- bad subtype", cp->u.subtype);
	       }
	      break;
	    }
	   case CI_ILLINST:	/* UNIX: send a SIGILL */
	    { char *subtype = 0;

	      switch (cp->u.subtype)
	       { 
		 case (CI_II_RADRMOD):
		  { subtype = "reserved addressing mode";
		    break;
		  }
		 case (CI_II_PRIVINST):
		  { subtype = "privileged instruction";
		    break;
		  }
		 case (CI_II_RESOPRND):
		  { subtype = "reserved operand";
		    break;
		  }
		 case (CI_II_BPT):
		  { subtype = "breakpoint trap"; /* UNIX makes SIGTRAP */
		    break;
		  }
	       }
	      if (subtype)
	       { sprintf (s, "illegal instruction, pc 0x%x (%s)", 
			  cp->pc, subtype);
	       }
	      else
	       { sprintf (s, "illegal instruction, pc 0x%x (%s %d)", 
			  cp->pc, "ERROR -- bad subtype", cp->u.subtype);
	       }
	      break;
	    }
	   case CI_TRACE:
	    { sprintf (s, "trace trap (!!??) -- better call John or Mike!");
	      break;
	    }
	   case CI_MEMFAULT:
	    { int faultbits = cp->u.memfault.bits;
	      int addr = cp->u.memfault.vaddr;

	      if (onunix)
	       { switch (faultbits)
		  { case (CI_MF_LENGTH | CI_MF_PAGE | CI_MF_READ | CI_MF_MEM):
		     { sprintf (s, 	/* non-existant virt space */
	"segmentation violation, addr = 0x%x pc = 0x%x", addr, cp->pc);
		       break;
		     }
		    case (CI_MF_PROT | CI_MF_PAGE | CI_MF_READ | CI_MF_MEM):
		     { sprintf (s,
	"bus error or page fault, addr = 0x%x pc = 0x%x", addr, cp->pc);
		       break;
		     }
		    case (CI_MF_PROT | CI_MF_PTE | CI_MF_READ | CI_MF_MEM):
		     { sprintf (s,
	"PANIC -- page table page fault! addr = 0x%x pc = 0x%x",addr, cp->pc);
		       break;
		     }
		    case (CI_MF_PROT | CI_MF_PAGE | CI_MF_READ | CI_MF_QBUS):
		     { sprintf (s,
	"Qbus access fault on read, addr = 0x%x pc = 0x%x\n", addr, cp->pc);
		       break;
		     }
		    case (CI_MF_PROT | CI_MF_PAGE | CI_MF_WRITE | CI_MF_QBUS):
		     { sprintf (s, 
	"Qbus access fault on write, addr = 0x%x pc = 0x%x\n", addr, cp->pc);
		       break;
		     }
		    default:
		     { sprintf (s,
		       "Strange memory fault (0x%x), addr = 0x%x pc = 0x%x",
		       addr, faultbits, cp->pc);
		       break;
		     }
		  }
	       }
	      else
	       { char *where, *what, *type, *access;

		 if ((faultbits & CI_MF_WHERE) == CI_MF_QBUS)
		  { where = "Qbus";
		  }
		 else
		  { where = "memory";
		  }
		 if ((faultbits & CI_MF_WHAT) == CI_MF_PTE)
		  { what = "pte";
		  }
		 else
		  { what = "page";
		  }
		 if ((faultbits & CI_MF_TYPE) == CI_MF_PROT)
		  { type = "protection";
		  }
		 else
		  { type = "length";
		  }
		 if ((faultbits & CI_MF_ACCESS) == CI_MF_READ)
		  { access = "read";
		  }
		 else
		  { access = "write";
		  }
		 sprintf (s,"%s %s %s violation on %s, addr = 0x%x pc = 0x%x",
			  where, what, type, access, addr, cp->pc);
	       }
	    }
	 }
	printf ("Stack trace follows:\n");
	for (k=0; k<KAC_MAXCALLS; k++)
	 { CRASHFRAME *frame = &cp->callstack[k];
	   if (!(frame->flags & CI_CF_VALID) ||
		(frame->flags & CI_CF_ARGLOST) ||
		(frame->nargs == 255) ||
		(frame->pc & 0x80000000))
	    { break;
	    }
	   printf (" %8x : ", frame->pc);
	   for (j=0; j<frame->nargs; j++)
	    { printf (" %8x", cp->callargs[frame->argindex+j]);
	    }
	   putchar ('\n');
	 }
}
