198944Sobrien/****************************************************************************
298944Sobrien
398944Sobrien		THIS SOFTWARE IS NOT COPYRIGHTED
498944Sobrien
598944Sobrien   HP offers the following for use in the public domain.  HP makes no
698944Sobrien   warranty with regard to the software or it's performance and the
798944Sobrien   user accepts the software "AS IS" with all faults.
898944Sobrien
998944Sobrien   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
1098944Sobrien   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1198944Sobrien   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1298944Sobrien
1398944Sobrien****************************************************************************/
1498944Sobrien
1598944Sobrien/****************************************************************************
1698944Sobrien *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
1798944Sobrien *
1898944Sobrien *  Module name: remcom.c $
1998944Sobrien *  Revision: 1.34 $
2098944Sobrien *  Date: 91/03/09 12:29:49 $
2198944Sobrien *  Contributor:     Lake Stevens Instrument Division$
2298944Sobrien *
2398944Sobrien *  Description:     low level support for gdb debugger. $
2498944Sobrien *
2598944Sobrien *  Considerations:  only works on target hardware $
2698944Sobrien *
2798944Sobrien *  Written by:      Glenn Engel $
2898944Sobrien *  ModuleState:     Experimental $
2998944Sobrien *
3098944Sobrien *  NOTES:           See Below $
3198944Sobrien *
3298944Sobrien *  Modified for SPARC by Stu Grossman, Cygnus Support.
3398944Sobrien *
3498944Sobrien *  This code has been extensively tested on the Fujitsu SPARClite demo board.
3598944Sobrien *
3698944Sobrien *  To enable debugger support, two things need to happen.  One, a
3798944Sobrien *  call to set_debug_traps() is necessary in order to allow any breakpoints
3898944Sobrien *  or error conditions to be properly intercepted and reported to gdb.
3998944Sobrien *  Two, a breakpoint needs to be generated to begin communication.  This
4098944Sobrien *  is most easily accomplished by a call to breakpoint().  Breakpoint()
4198944Sobrien *  simulates a breakpoint by executing a trap #1.
4298944Sobrien *
4398944Sobrien *************
4498944Sobrien *
4598944Sobrien *    The following gdb commands are supported:
4698944Sobrien *
4798944Sobrien * command          function                               Return value
4898944Sobrien *
4998944Sobrien *    g             return the value of the CPU registers  hex data or ENN
5098944Sobrien *    G             set the value of the CPU registers     OK or ENN
5198944Sobrien *
5298944Sobrien *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
5398944Sobrien *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
5498944Sobrien *
5598944Sobrien *    c             Resume at current address              SNN   ( signal NN)
5698944Sobrien *    cAA..AA       Continue at address AA..AA             SNN
5798944Sobrien *
5898944Sobrien *    s             Step one instruction                   SNN
5998944Sobrien *    sAA..AA       Step one instruction from AA..AA       SNN
6098944Sobrien *
6198944Sobrien *    k             kill
6298944Sobrien *
6398944Sobrien *    ?             What was the last sigval ?             SNN   (signal NN)
6498944Sobrien *
6598944Sobrien * All commands and responses are sent with a packet which includes a
6698944Sobrien * checksum.  A packet consists of
6798944Sobrien *
6898944Sobrien * $<packet info>#<checksum>.
6998944Sobrien *
7098944Sobrien * where
7198944Sobrien * <packet info> :: <characters representing the command or response>
7298944Sobrien * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
7398944Sobrien *
7498944Sobrien * When a packet is received, it is first acknowledged with either '+' or '-'.
7598944Sobrien * '+' indicates a successful transfer.  '-' indicates a failed transfer.
7698944Sobrien *
7798944Sobrien * Example:
7898944Sobrien *
7998944Sobrien * Host:                  Reply:
8098944Sobrien * $m0,10#2a               +$00010203040506070809101112131415#42
8198944Sobrien *
8298944Sobrien ****************************************************************************/
8398944Sobrien
8498944Sobrien#include <string.h>
8598944Sobrien#include <signal.h>
8698944Sobrien
8798944Sobrien/************************************************************************
8898944Sobrien *
8998944Sobrien * external low-level support routines
9098944Sobrien */
9198944Sobrien
9298944Sobrienextern void putDebugChar();	/* write a single character      */
9398944Sobrienextern int getDebugChar();	/* read and return a single char */
9498944Sobrien
9598944Sobrien/************************************************************************/
9698944Sobrien/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
9798944Sobrien/* at least NUMREGBYTES*2 are needed for register packets */
9898944Sobrien#define BUFMAX 2048
9998944Sobrien
10098944Sobrienstatic int initialized = 0;	/* !0 means we've been initialized */
10198944Sobrien
10298944Sobrienstatic void set_mem_fault_trap();
10398944Sobrien
10498944Sobrienstatic const char hexchars[]="0123456789abcdef";
10598944Sobrien
10698944Sobrien#define NUMREGS 72
10798944Sobrien
10898944Sobrien/* Number of bytes of registers.  */
10998944Sobrien#define NUMREGBYTES (NUMREGS * 4)
11098944Sobrienenum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
11198944Sobrien		 O0, O1, O2, O3, O4, O5, SP, O7,
11298944Sobrien		 L0, L1, L2, L3, L4, L5, L6, L7,
11398944Sobrien		 I0, I1, I2, I3, I4, I5, FP, I7,
11498944Sobrien
11598944Sobrien		 F0, F1, F2, F3, F4, F5, F6, F7,
11698944Sobrien		 F8, F9, F10, F11, F12, F13, F14, F15,
11798944Sobrien		 F16, F17, F18, F19, F20, F21, F22, F23,
11898944Sobrien		 F24, F25, F26, F27, F28, F29, F30, F31,
11998944Sobrien		 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
12098944Sobrien
12198944Sobrien/***************************  ASSEMBLY CODE MACROS *************************/
12298944Sobrien/* 									   */
12398944Sobrien
12498944Sobrienextern void trap_low();
12598944Sobrien
12698944Sobrienasm("
12798944Sobrien	.reserve trapstack, 1000 * 4, \"bss\", 8
12898944Sobrien
12998944Sobrien	.data
13098944Sobrien	.align	4
13198944Sobrien
13298944Sobrienin_trap_handler:
13398944Sobrien	.word	0
13498944Sobrien
13598944Sobrien	.text
13698944Sobrien	.align 4
13798944Sobrien
13898944Sobrien! This function is called when any SPARC trap (except window overflow or
13998944Sobrien! underflow) occurs.  It makes sure that the invalid register window is still
14098944Sobrien! available before jumping into C code.  It will also restore the world if you
14198944Sobrien! return from handle_exception.
14298944Sobrien
14398944Sobrien	.globl _trap_low
14498944Sobrien_trap_low:
14598944Sobrien	mov	%psr, %l0
14698944Sobrien	mov	%wim, %l3
14798944Sobrien
14898944Sobrien	srl	%l3, %l0, %l4		! wim >> cwp
14998944Sobrien	cmp	%l4, 1
15098944Sobrien	bne	window_fine		! Branch if not in the invalid window
15198944Sobrien	nop
15298944Sobrien
15398944Sobrien! Handle window overflow
15498944Sobrien
15598944Sobrien	mov	%g1, %l4		! Save g1, we use it to hold the wim
15698944Sobrien	srl	%l3, 1, %g1		! Rotate wim right
15798944Sobrien	tst	%g1
15898944Sobrien	bg	good_wim		! Branch if new wim is non-zero
15998944Sobrien	nop
16098944Sobrien
16198944Sobrien! At this point, we need to bring a 1 into the high order bit of the wim.
16298944Sobrien! Since we don't want to make any assumptions about the number of register
16398944Sobrien! windows, we figure it out dynamically so as to setup the wim correctly.
16498944Sobrien
16598944Sobrien	not	%g1			! Fill g1 with ones
16698944Sobrien	mov	%g1, %wim		! Fill the wim with ones
16798944Sobrien	nop
16898944Sobrien	nop
16998944Sobrien	nop
17098944Sobrien	mov	%wim, %g1		! Read back the wim
17198944Sobrien	inc	%g1			! Now g1 has 1 just to left of wim
17298944Sobrien	srl	%g1, 1, %g1		! Now put 1 at top of wim
17398944Sobrien	mov	%g0, %wim		! Clear wim so that subsequent save
17498944Sobrien	nop				!  won't trap
17598944Sobrien	nop
17698944Sobrien	nop
17798944Sobrien
17898944Sobriengood_wim:
17998944Sobrien	save	%g0, %g0, %g0		! Slip into next window
18098944Sobrien	mov	%g1, %wim		! Install the new wim
18198944Sobrien
18298944Sobrien	std	%l0, [%sp + 0 * 4]	! save L & I registers
18398944Sobrien	std	%l2, [%sp + 2 * 4]
18498944Sobrien	std	%l4, [%sp + 4 * 4]
18598944Sobrien	std	%l6, [%sp + 6 * 4]
18698944Sobrien
18798944Sobrien	std	%i0, [%sp + 8 * 4]
18898944Sobrien	std	%i2, [%sp + 10 * 4]
18998944Sobrien	std	%i4, [%sp + 12 * 4]
19098944Sobrien	std	%i6, [%sp + 14 * 4]
19198944Sobrien
19298944Sobrien	restore				! Go back to trap window.
19398944Sobrien	mov	%l4, %g1		! Restore %g1
19498944Sobrien
19598944Sobrienwindow_fine:
19698944Sobrien	sethi	%hi(in_trap_handler), %l4
19798944Sobrien	ld	[%lo(in_trap_handler) + %l4], %l5
19898944Sobrien	tst	%l5
19998944Sobrien	bg	recursive_trap
20098944Sobrien	inc	%l5
20198944Sobrien
20298944Sobrien	set	trapstack+1000*4, %sp	! Switch to trap stack
20398944Sobrien
20498944Sobrienrecursive_trap:
20598944Sobrien	st	%l5, [%lo(in_trap_handler) + %l4]
20698944Sobrien	sub	%sp,(16+1+6+1+72)*4,%sp	! Make room for input & locals
20798944Sobrien 					! + hidden arg + arg spill
20898944Sobrien					! + doubleword alignment
20998944Sobrien					! + registers[72] local var
21098944Sobrien
21198944Sobrien	std	%g0, [%sp + (24 + 0) * 4] ! registers[Gx]
21298944Sobrien	std	%g2, [%sp + (24 + 2) * 4]
21398944Sobrien	std	%g4, [%sp + (24 + 4) * 4]
21498944Sobrien	std	%g6, [%sp + (24 + 6) * 4]
21598944Sobrien
21698944Sobrien	std	%i0, [%sp + (24 + 8) * 4] ! registers[Ox]
21798944Sobrien	std	%i2, [%sp + (24 + 10) * 4]
21898944Sobrien	std	%i4, [%sp + (24 + 12) * 4]
21998944Sobrien	std	%i6, [%sp + (24 + 14) * 4]
22098944Sobrien					! F0->F31 not implemented
22198944Sobrien	mov	%y, %l4
22298944Sobrien	mov	%tbr, %l5
22398944Sobrien	st	%l4, [%sp + (24 + 64) * 4] ! Y
22498944Sobrien	st	%l0, [%sp + (24 + 65) * 4] ! PSR
22598944Sobrien	st	%l3, [%sp + (24 + 66) * 4] ! WIM
22698944Sobrien	st	%l5, [%sp + (24 + 67) * 4] ! TBR
22798944Sobrien	st	%l1, [%sp + (24 + 68) * 4] ! PC
22898944Sobrien	st	%l2, [%sp + (24 + 69) * 4] ! NPC
22998944Sobrien
23098944Sobrien					! CPSR and FPSR not impl
23198944Sobrien
23298944Sobrien	or	%l0, 0xf20, %l4
23398944Sobrien	mov	%l4, %psr		! Turn on traps, disable interrupts
23498944Sobrien
23598944Sobrien	call	_handle_exception
23698944Sobrien	add	%sp, 24 * 4, %o0	! Pass address of registers
23798944Sobrien
23898944Sobrien! Reload all of the registers that aren't on the stack
23998944Sobrien
24098944Sobrien	ld	[%sp + (24 + 1) * 4], %g1 ! registers[Gx]
24198944Sobrien	ldd	[%sp + (24 + 2) * 4], %g2
24298944Sobrien	ldd	[%sp + (24 + 4) * 4], %g4
24398944Sobrien	ldd	[%sp + (24 + 6) * 4], %g6
24498944Sobrien
24598944Sobrien	ldd	[%sp + (24 + 8) * 4], %i0 ! registers[Ox]
24698944Sobrien	ldd	[%sp + (24 + 10) * 4], %i2
24798944Sobrien	ldd	[%sp + (24 + 12) * 4], %i4
24898944Sobrien	ldd	[%sp + (24 + 14) * 4], %i6
24998944Sobrien
25098944Sobrien	ldd	[%sp + (24 + 64) * 4], %l0 ! Y & PSR
25198944Sobrien	ldd	[%sp + (24 + 68) * 4], %l2 ! PC & NPC
25298944Sobrien
25398944Sobrien	restore				! Ensure that previous window is valid
25498944Sobrien	save	%g0, %g0, %g0		!  by causing a window_underflow trap
25598944Sobrien
25698944Sobrien	mov	%l0, %y
25798944Sobrien	mov	%l1, %psr		! Make sure that traps are disabled
25898944Sobrien					! for rett
25998944Sobrien
26098944Sobrien	sethi	%hi(in_trap_handler), %l4
26198944Sobrien	ld	[%lo(in_trap_handler) + %l4], %l5
26298944Sobrien	dec	%l5
26398944Sobrien	st	%l5, [%lo(in_trap_handler) + %l4]
26498944Sobrien
26598944Sobrien	jmpl	%l2, %g0		! Restore old PC
26698944Sobrien	rett	%l3			! Restore old nPC
26798944Sobrien");
26898944Sobrien
26998944Sobrien/* Convert ch from a hex digit to an int */
27098944Sobrien
27198944Sobrienstatic int
27298944Sobrienhex (unsigned char ch)
27398944Sobrien{
27498944Sobrien  if (ch >= 'a' && ch <= 'f')
27598944Sobrien    return ch-'a'+10;
27698944Sobrien  if (ch >= '0' && ch <= '9')
27798944Sobrien    return ch-'0';
27898944Sobrien  if (ch >= 'A' && ch <= 'F')
27998944Sobrien    return ch-'A'+10;
28098944Sobrien  return -1;
28198944Sobrien}
28298944Sobrien
28398944Sobrienstatic char remcomInBuffer[BUFMAX];
28498944Sobrienstatic char remcomOutBuffer[BUFMAX];
28598944Sobrien
28698944Sobrien/* scan for the sequence $<data>#<checksum>     */
28798944Sobrien
28898944Sobrienunsigned char *
28998944Sobriengetpacket (void)
29098944Sobrien{
29198944Sobrien  unsigned char *buffer = &remcomInBuffer[0];
29298944Sobrien  unsigned char checksum;
29398944Sobrien  unsigned char xmitcsum;
29498944Sobrien  int count;
29598944Sobrien  char ch;
29698944Sobrien
29798944Sobrien  while (1)
29898944Sobrien    {
29998944Sobrien      /* wait around for the start character, ignore all other characters */
30098944Sobrien      while ((ch = getDebugChar ()) != '$')
30198944Sobrien	;
30298944Sobrien
30398944Sobrienretry:
30498944Sobrien      checksum = 0;
30598944Sobrien      xmitcsum = -1;
30698944Sobrien      count = 0;
30798944Sobrien
30898944Sobrien      /* now, read until a # or end of buffer is found */
30998944Sobrien      while (count < BUFMAX)
31098944Sobrien	{
31198944Sobrien	  ch = getDebugChar ();
31298944Sobrien          if (ch == '$')
31398944Sobrien            goto retry;
31498944Sobrien	  if (ch == '#')
31598944Sobrien	    break;
31698944Sobrien	  checksum = checksum + ch;
31798944Sobrien	  buffer[count] = ch;
31898944Sobrien	  count = count + 1;
31998944Sobrien	}
32098944Sobrien      buffer[count] = 0;
32198944Sobrien
32298944Sobrien      if (ch == '#')
32398944Sobrien	{
32498944Sobrien	  ch = getDebugChar ();
32598944Sobrien	  xmitcsum = hex (ch) << 4;
32698944Sobrien	  ch = getDebugChar ();
32798944Sobrien	  xmitcsum += hex (ch);
32898944Sobrien
32998944Sobrien	  if (checksum != xmitcsum)
33098944Sobrien	    {
33198944Sobrien	      putDebugChar ('-');	/* failed checksum */
33298944Sobrien	    }
33398944Sobrien	  else
33498944Sobrien	    {
33598944Sobrien	      putDebugChar ('+');	/* successful transfer */
33698944Sobrien
33798944Sobrien	      /* if a sequence char is present, reply the sequence ID */
33898944Sobrien	      if (buffer[2] == ':')
33998944Sobrien		{
34098944Sobrien		  putDebugChar (buffer[0]);
34198944Sobrien		  putDebugChar (buffer[1]);
34298944Sobrien
34398944Sobrien		  return &buffer[3];
34498944Sobrien		}
34598944Sobrien
34698944Sobrien	      return &buffer[0];
34798944Sobrien	    }
34898944Sobrien	}
34998944Sobrien    }
35098944Sobrien}
35198944Sobrien
35298944Sobrien/* send the packet in buffer.  */
35398944Sobrien
35498944Sobrienstatic void
35598944Sobrienputpacket (unsigned char *buffer)
35698944Sobrien{
35798944Sobrien  unsigned char checksum;
35898944Sobrien  int count;
35998944Sobrien  unsigned char ch;
36098944Sobrien
36198944Sobrien  /*  $<packet info>#<checksum>. */
36298944Sobrien  do
36398944Sobrien    {
36498944Sobrien      putDebugChar('$');
36598944Sobrien      checksum = 0;
36698944Sobrien      count = 0;
36798944Sobrien
36898944Sobrien      while (ch = buffer[count])
36998944Sobrien	{
37098944Sobrien	  putDebugChar(ch);
37198944Sobrien	  checksum += ch;
37298944Sobrien	  count += 1;
37398944Sobrien	}
37498944Sobrien
37598944Sobrien      putDebugChar('#');
37698944Sobrien      putDebugChar(hexchars[checksum >> 4]);
37798944Sobrien      putDebugChar(hexchars[checksum & 0xf]);
37898944Sobrien
37998944Sobrien    }
38098944Sobrien  while (getDebugChar() != '+');
38198944Sobrien}
38298944Sobrien
38398944Sobrien/* Indicate to caller of mem2hex or hex2mem that there has been an
38498944Sobrien   error.  */
38598944Sobrienstatic volatile int mem_err = 0;
38698944Sobrien
38798944Sobrien/* Convert the memory pointed to by mem into hex, placing result in buf.
38898944Sobrien * Return a pointer to the last char put in buf (null), in case of mem fault,
38998944Sobrien * return 0.
39098944Sobrien * If MAY_FAULT is non-zero, then we will handle memory faults by returning
39198944Sobrien * a 0, else treat a fault like any other fault in the stub.
39298944Sobrien */
39398944Sobrien
39498944Sobrienstatic unsigned char *
39598944Sobrienmem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
39698944Sobrien{
39798944Sobrien  unsigned char ch;
39898944Sobrien
39998944Sobrien  set_mem_fault_trap(may_fault);
40098944Sobrien
40198944Sobrien  while (count-- > 0)
40298944Sobrien    {
40398944Sobrien      ch = *mem++;
40498944Sobrien      if (mem_err)
40598944Sobrien	return 0;
40698944Sobrien      *buf++ = hexchars[ch >> 4];
40798944Sobrien      *buf++ = hexchars[ch & 0xf];
40898944Sobrien    }
40998944Sobrien
41098944Sobrien  *buf = 0;
41198944Sobrien
41298944Sobrien  set_mem_fault_trap(0);
41398944Sobrien
41498944Sobrien  return buf;
41598944Sobrien}
41698944Sobrien
41798944Sobrien/* convert the hex array pointed to by buf into binary to be placed in mem
41898944Sobrien * return a pointer to the character AFTER the last byte written */
41998944Sobrien
42098944Sobrienstatic char *
42198944Sobrienhex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
42298944Sobrien{
42398944Sobrien  int i;
42498944Sobrien  unsigned char ch;
42598944Sobrien
42698944Sobrien  set_mem_fault_trap(may_fault);
42798944Sobrien
42898944Sobrien  for (i=0; i<count; i++)
42998944Sobrien    {
43098944Sobrien      ch = hex(*buf++) << 4;
43198944Sobrien      ch |= hex(*buf++);
43298944Sobrien      *mem++ = ch;
43398944Sobrien      if (mem_err)
43498944Sobrien	return 0;
43598944Sobrien    }
43698944Sobrien
43798944Sobrien  set_mem_fault_trap(0);
43898944Sobrien
43998944Sobrien  return mem;
44098944Sobrien}
44198944Sobrien
44298944Sobrien/* This table contains the mapping between SPARC hardware trap types, and
44398944Sobrien   signals, which are primarily what GDB understands.  It also indicates
44498944Sobrien   which hardware traps we need to commandeer when initializing the stub. */
44598944Sobrien
44698944Sobrienstatic struct hard_trap_info
44798944Sobrien{
44898944Sobrien  unsigned char tt;		/* Trap type code for SPARClite */
44998944Sobrien  unsigned char signo;		/* Signal that we map this trap into */
45098944Sobrien} hard_trap_info[] = {
45198944Sobrien  {1, SIGSEGV},			/* instruction access error */
45298944Sobrien  {2, SIGILL},			/* privileged instruction */
45398944Sobrien  {3, SIGILL},			/* illegal instruction */
45498944Sobrien  {4, SIGEMT},			/* fp disabled */
45598944Sobrien  {36, SIGEMT},			/* cp disabled */
45698944Sobrien  {7, SIGBUS},			/* mem address not aligned */
45798944Sobrien  {9, SIGSEGV},			/* data access exception */
45898944Sobrien  {10, SIGEMT},			/* tag overflow */
45998944Sobrien  {128+1, SIGTRAP},		/* ta 1 - normal breakpoint instruction */
46098944Sobrien  {0, 0}			/* Must be last */
46198944Sobrien};
46298944Sobrien
46398944Sobrien/* Set up exception handlers for tracing and breakpoints */
46498944Sobrien
46598944Sobrienvoid
46698944Sobrienset_debug_traps (void)
46798944Sobrien{
46898944Sobrien  struct hard_trap_info *ht;
46998944Sobrien
47098944Sobrien  for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
47198944Sobrien    exceptionHandler(ht->tt, trap_low);
47298944Sobrien
47398944Sobrien  initialized = 1;
47498944Sobrien}
47598944Sobrien
47698944Sobrienasm ("
47798944Sobrien! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
47898944Sobrien! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
47998944Sobrien! 0 would ever contain code that could mem fault.  This routine will skip
48098944Sobrien! past the faulting instruction after setting mem_err.
48198944Sobrien
48298944Sobrien	.text
48398944Sobrien	.align 4
48498944Sobrien
48598944Sobrien_fltr_set_mem_err:
48698944Sobrien	sethi %hi(_mem_err), %l0
48798944Sobrien	st %l1, [%l0 + %lo(_mem_err)]
48898944Sobrien	jmpl %l2, %g0
48998944Sobrien	rett %l2+4
49098944Sobrien");
49198944Sobrien
49298944Sobrienstatic void
49398944Sobrienset_mem_fault_trap (int enable)
49498944Sobrien{
49598944Sobrien  extern void fltr_set_mem_err();
49698944Sobrien  mem_err = 0;
49798944Sobrien
49898944Sobrien  if (enable)
49998944Sobrien    exceptionHandler(9, fltr_set_mem_err);
50098944Sobrien  else
50198944Sobrien    exceptionHandler(9, trap_low);
50298944Sobrien}
50398944Sobrien
50498944Sobrien/* Convert the SPARC hardware trap type code to a unix signal number. */
50598944Sobrien
50698944Sobrienstatic int
50798944SobriencomputeSignal (int tt)
50898944Sobrien{
50998944Sobrien  struct hard_trap_info *ht;
51098944Sobrien
51198944Sobrien  for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
51298944Sobrien    if (ht->tt == tt)
51398944Sobrien      return ht->signo;
51498944Sobrien
51598944Sobrien  return SIGHUP;		/* default for things we don't know about */
51698944Sobrien}
51798944Sobrien
51898944Sobrien/*
51998944Sobrien * While we find nice hex chars, build an int.
52098944Sobrien * Return number of chars processed.
52198944Sobrien */
52298944Sobrien
52398944Sobrienstatic int
52498944SobrienhexToInt(char **ptr, int *intValue)
52598944Sobrien{
52698944Sobrien  int numChars = 0;
52798944Sobrien  int hexValue;
52898944Sobrien
52998944Sobrien  *intValue = 0;
53098944Sobrien
53198944Sobrien  while (**ptr)
53298944Sobrien    {
53398944Sobrien      hexValue = hex(**ptr);
53498944Sobrien      if (hexValue < 0)
53598944Sobrien	break;
53698944Sobrien
53798944Sobrien      *intValue = (*intValue << 4) | hexValue;
53898944Sobrien      numChars ++;
53998944Sobrien
54098944Sobrien      (*ptr)++;
54198944Sobrien    }
54298944Sobrien
54398944Sobrien  return (numChars);
54498944Sobrien}
54598944Sobrien
54698944Sobrien/*
54798944Sobrien * This function does all command procesing for interfacing to gdb.  It
54898944Sobrien * returns 1 if you should skip the instruction at the trap address, 0
54998944Sobrien * otherwise.
55098944Sobrien */
55198944Sobrien
55298944Sobrienextern void breakinst();
55398944Sobrien
55498944Sobrienstatic void
55598944Sobrienhandle_exception (unsigned long *registers)
55698944Sobrien{
55798944Sobrien  int tt;			/* Trap type */
55898944Sobrien  int sigval;
55998944Sobrien  int addr;
56098944Sobrien  int length;
56198944Sobrien  char *ptr;
56298944Sobrien  unsigned long *sp;
56398944Sobrien
56498944Sobrien/* First, we must force all of the windows to be spilled out */
56598944Sobrien
56698944Sobrien  asm("	save %sp, -64, %sp
56798944Sobrien	save %sp, -64, %sp
56898944Sobrien	save %sp, -64, %sp
56998944Sobrien	save %sp, -64, %sp
57098944Sobrien	save %sp, -64, %sp
57198944Sobrien	save %sp, -64, %sp
57298944Sobrien	save %sp, -64, %sp
57398944Sobrien	save %sp, -64, %sp
57498944Sobrien	restore
57598944Sobrien	restore
57698944Sobrien	restore
57798944Sobrien	restore
57898944Sobrien	restore
57998944Sobrien	restore
58098944Sobrien	restore
58198944Sobrien	restore
58298944Sobrien");
58398944Sobrien
58498944Sobrien  if (registers[PC] == (unsigned long)breakinst)
58598944Sobrien    {
58698944Sobrien      registers[PC] = registers[NPC];
58798944Sobrien      registers[NPC] += 4;
58898944Sobrien    }
58998944Sobrien
59098944Sobrien  sp = (unsigned long *)registers[SP];
59198944Sobrien
59298944Sobrien  tt = (registers[TBR] >> 4) & 0xff;
59398944Sobrien
59498944Sobrien  /* reply to host that an exception has occurred */
59598944Sobrien  sigval = computeSignal(tt);
59698944Sobrien  ptr = remcomOutBuffer;
59798944Sobrien
59898944Sobrien  *ptr++ = 'T';
59998944Sobrien  *ptr++ = hexchars[sigval >> 4];
60098944Sobrien  *ptr++ = hexchars[sigval & 0xf];
60198944Sobrien
60298944Sobrien  *ptr++ = hexchars[PC >> 4];
60398944Sobrien  *ptr++ = hexchars[PC & 0xf];
60498944Sobrien  *ptr++ = ':';
60598944Sobrien  ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
60698944Sobrien  *ptr++ = ';';
60798944Sobrien
60898944Sobrien  *ptr++ = hexchars[FP >> 4];
60998944Sobrien  *ptr++ = hexchars[FP & 0xf];
61098944Sobrien  *ptr++ = ':';
61198944Sobrien  ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
61298944Sobrien  *ptr++ = ';';
61398944Sobrien
61498944Sobrien  *ptr++ = hexchars[SP >> 4];
61598944Sobrien  *ptr++ = hexchars[SP & 0xf];
61698944Sobrien  *ptr++ = ':';
61798944Sobrien  ptr = mem2hex((char *)&sp, ptr, 4, 0);
61898944Sobrien  *ptr++ = ';';
61998944Sobrien
62098944Sobrien  *ptr++ = hexchars[NPC >> 4];
62198944Sobrien  *ptr++ = hexchars[NPC & 0xf];
62298944Sobrien  *ptr++ = ':';
62398944Sobrien  ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
62498944Sobrien  *ptr++ = ';';
62598944Sobrien
62698944Sobrien  *ptr++ = hexchars[O7 >> 4];
62798944Sobrien  *ptr++ = hexchars[O7 & 0xf];
62898944Sobrien  *ptr++ = ':';
62998944Sobrien  ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
63098944Sobrien  *ptr++ = ';';
63198944Sobrien
63298944Sobrien  *ptr++ = 0;
63398944Sobrien
63498944Sobrien  putpacket(remcomOutBuffer);
63598944Sobrien
63698944Sobrien  while (1)
63798944Sobrien    {
63898944Sobrien      remcomOutBuffer[0] = 0;
63998944Sobrien
64098944Sobrien      ptr = getpacket();
64198944Sobrien      switch (*ptr++)
64298944Sobrien	{
64398944Sobrien	case '?':
64498944Sobrien	  remcomOutBuffer[0] = 'S';
64598944Sobrien	  remcomOutBuffer[1] = hexchars[sigval >> 4];
64698944Sobrien	  remcomOutBuffer[2] = hexchars[sigval & 0xf];
64798944Sobrien	  remcomOutBuffer[3] = 0;
64898944Sobrien	  break;
64998944Sobrien
65098944Sobrien	case 'd':		/* toggle debug flag */
65198944Sobrien	  break;
65298944Sobrien
65398944Sobrien	case 'g':		/* return the value of the CPU registers */
65498944Sobrien	  {
65598944Sobrien	    ptr = remcomOutBuffer;
65698944Sobrien	    ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
65798944Sobrien	    ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
65898944Sobrien	    memset(ptr, '0', 32 * 8); /* Floating point */
65998944Sobrien	    mem2hex((char *)&registers[Y],
66098944Sobrien		    ptr + 32 * 4 * 2,
66198944Sobrien		    8 * 4,
66298944Sobrien		    0);		/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
66398944Sobrien	  }
66498944Sobrien	  break;
66598944Sobrien
66698944Sobrien	case 'G':	   /* set the value of the CPU registers - return OK */
66798944Sobrien	  {
66898944Sobrien	    unsigned long *newsp, psr;
66998944Sobrien
67098944Sobrien	    psr = registers[PSR];
67198944Sobrien
67298944Sobrien	    hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
67398944Sobrien	    hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
67498944Sobrien	    hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
67598944Sobrien		    8 * 4, 0);	/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
67698944Sobrien
67798944Sobrien	    /* See if the stack pointer has moved.  If so, then copy the saved
67898944Sobrien	       locals and ins to the new location.  This keeps the window
67998944Sobrien	       overflow and underflow routines happy.  */
68098944Sobrien
68198944Sobrien	    newsp = (unsigned long *)registers[SP];
68298944Sobrien	    if (sp != newsp)
68398944Sobrien	      sp = memcpy(newsp, sp, 16 * 4);
68498944Sobrien
68598944Sobrien	    /* Don't allow CWP to be modified. */
68698944Sobrien
68798944Sobrien	    if (psr != registers[PSR])
68898944Sobrien	      registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
68998944Sobrien
69098944Sobrien	    strcpy(remcomOutBuffer,"OK");
69198944Sobrien	  }
69298944Sobrien	  break;
69398944Sobrien
69498944Sobrien	case 'm':	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
69598944Sobrien	  /* Try to read %x,%x.  */
69698944Sobrien
69798944Sobrien	  if (hexToInt(&ptr, &addr)
69898944Sobrien	      && *ptr++ == ','
69998944Sobrien	      && hexToInt(&ptr, &length))
70098944Sobrien	    {
70198944Sobrien	      if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
70298944Sobrien		break;
70398944Sobrien
70498944Sobrien	      strcpy (remcomOutBuffer, "E03");
70598944Sobrien	    }
70698944Sobrien	  else
70798944Sobrien	    strcpy(remcomOutBuffer,"E01");
70898944Sobrien	  break;
70998944Sobrien
71098944Sobrien	case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
71198944Sobrien	  /* Try to read '%x,%x:'.  */
71298944Sobrien
71398944Sobrien	  if (hexToInt(&ptr, &addr)
71498944Sobrien	      && *ptr++ == ','
71598944Sobrien	      && hexToInt(&ptr, &length)
71698944Sobrien	      && *ptr++ == ':')
71798944Sobrien	    {
71898944Sobrien	      if (hex2mem(ptr, (char *)addr, length, 1))
71998944Sobrien		strcpy(remcomOutBuffer, "OK");
72098944Sobrien	      else
72198944Sobrien		strcpy(remcomOutBuffer, "E03");
72298944Sobrien	    }
72398944Sobrien	  else
72498944Sobrien	    strcpy(remcomOutBuffer, "E02");
72598944Sobrien	  break;
72698944Sobrien
72798944Sobrien	case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
72898944Sobrien	  /* try to read optional parameter, pc unchanged if no parm */
72998944Sobrien
73098944Sobrien	  if (hexToInt(&ptr, &addr))
73198944Sobrien	    {
73298944Sobrien	      registers[PC] = addr;
73398944Sobrien	      registers[NPC] = addr + 4;
73498944Sobrien	    }
73598944Sobrien
73698944Sobrien/* Need to flush the instruction cache here, as we may have deposited a
73798944Sobrien   breakpoint, and the icache probably has no way of knowing that a data ref to
73898944Sobrien   some location may have changed something that is in the instruction cache.
73998944Sobrien */
74098944Sobrien
74198944Sobrien	  flush_i_cache();
74298944Sobrien	  return;
74398944Sobrien
74498944Sobrien	  /* kill the program */
74598944Sobrien	case 'k' :		/* do nothing */
74698944Sobrien	  break;
74798944Sobrien#if 0
74898944Sobrien	case 't':		/* Test feature */
74998944Sobrien	  asm (" std %f30,[%sp]");
75098944Sobrien	  break;
75198944Sobrien#endif
75298944Sobrien	case 'r':		/* Reset */
75398944Sobrien	  asm ("call 0
75498944Sobrien		nop ");
75598944Sobrien	  break;
75698944Sobrien	}			/* switch */
75798944Sobrien
75898944Sobrien      /* reply to the request */
75998944Sobrien      putpacket(remcomOutBuffer);
76098944Sobrien    }
76198944Sobrien}
76298944Sobrien
76398944Sobrien/* This function will generate a breakpoint exception.  It is used at the
76498944Sobrien   beginning of a program to sync up with a debugger and can be used
76598944Sobrien   otherwise as a quick means to stop program execution and "break" into
76698944Sobrien   the debugger. */
76798944Sobrien
76898944Sobrienvoid
76998944Sobrienbreakpoint (void)
77098944Sobrien{
77198944Sobrien  if (!initialized)
77298944Sobrien    return;
77398944Sobrien
77498944Sobrien  asm("	.globl _breakinst
77598944Sobrien
77698944Sobrien	_breakinst: ta 1
77798944Sobrien      ");
77898944Sobrien}
779