1*48596154Schristos /****************************************************************************
2*48596154Schristos
3*48596154Schristos THIS SOFTWARE IS NOT COPYRIGHTED
4*48596154Schristos
5*48596154Schristos HP offers the following for use in the public domain. HP makes no
6*48596154Schristos warranty with regard to the software or it's performance and the
7*48596154Schristos user accepts the software "AS IS" with all faults.
8*48596154Schristos
9*48596154Schristos HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10*48596154Schristos TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11*48596154Schristos OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12*48596154Schristos
13*48596154Schristos ****************************************************************************/
14*48596154Schristos
15*48596154Schristos /****************************************************************************
16*48596154Schristos * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17*48596154Schristos *
18*48596154Schristos * Module name: remcom.c $
19*48596154Schristos * Revision: 1.34 $
20*48596154Schristos * Date: 91/03/09 12:29:49 $
21*48596154Schristos * Contributor: Lake Stevens Instrument Division$
22*48596154Schristos *
23*48596154Schristos * Description: low level support for gdb debugger. $
24*48596154Schristos *
25*48596154Schristos * Considerations: only works on target hardware $
26*48596154Schristos *
27*48596154Schristos * Written by: Glenn Engel $
28*48596154Schristos * ModuleState: Experimental $
29*48596154Schristos *
30*48596154Schristos * NOTES: See Below $
31*48596154Schristos *
32*48596154Schristos * Modified for SPARC by Stu Grossman, Cygnus Support.
33*48596154Schristos *
34*48596154Schristos * This code has been extensively tested on the Fujitsu SPARClite demo board.
35*48596154Schristos *
36*48596154Schristos * To enable debugger support, two things need to happen. One, a
37*48596154Schristos * call to set_debug_traps() is necessary in order to allow any breakpoints
38*48596154Schristos * or error conditions to be properly intercepted and reported to gdb.
39*48596154Schristos * Two, a breakpoint needs to be generated to begin communication. This
40*48596154Schristos * is most easily accomplished by a call to breakpoint(). Breakpoint()
41*48596154Schristos * simulates a breakpoint by executing a trap #1.
42*48596154Schristos *
43*48596154Schristos *************
44*48596154Schristos *
45*48596154Schristos * The following gdb commands are supported:
46*48596154Schristos *
47*48596154Schristos * command function Return value
48*48596154Schristos *
49*48596154Schristos * g return the value of the CPU registers hex data or ENN
50*48596154Schristos * G set the value of the CPU registers OK or ENN
51*48596154Schristos *
52*48596154Schristos * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
53*48596154Schristos * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
54*48596154Schristos *
55*48596154Schristos * c Resume at current address SNN ( signal NN)
56*48596154Schristos * cAA..AA Continue at address AA..AA SNN
57*48596154Schristos *
58*48596154Schristos * s Step one instruction SNN
59*48596154Schristos * sAA..AA Step one instruction from AA..AA SNN
60*48596154Schristos *
61*48596154Schristos * k kill
62*48596154Schristos *
63*48596154Schristos * ? What was the last sigval ? SNN (signal NN)
64*48596154Schristos *
65*48596154Schristos * All commands and responses are sent with a packet which includes a
66*48596154Schristos * checksum. A packet consists of
67*48596154Schristos *
68*48596154Schristos * $<packet info>#<checksum>.
69*48596154Schristos *
70*48596154Schristos * where
71*48596154Schristos * <packet info> :: <characters representing the command or response>
72*48596154Schristos * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
73*48596154Schristos *
74*48596154Schristos * When a packet is received, it is first acknowledged with either '+' or '-'.
75*48596154Schristos * '+' indicates a successful transfer. '-' indicates a failed transfer.
76*48596154Schristos *
77*48596154Schristos * Example:
78*48596154Schristos *
79*48596154Schristos * Host: Reply:
80*48596154Schristos * $m0,10#2a +$00010203040506070809101112131415#42
81*48596154Schristos *
82*48596154Schristos ****************************************************************************/
83*48596154Schristos
84*48596154Schristos #include <string.h>
85*48596154Schristos #include <signal.h>
86*48596154Schristos
87*48596154Schristos /************************************************************************
88*48596154Schristos *
89*48596154Schristos * external low-level support routines
90*48596154Schristos */
91*48596154Schristos
92*48596154Schristos extern void putDebugChar(); /* write a single character */
93*48596154Schristos extern int getDebugChar(); /* read and return a single char */
94*48596154Schristos
95*48596154Schristos /************************************************************************/
96*48596154Schristos /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
97*48596154Schristos /* at least NUMREGBYTES*2 are needed for register packets */
98*48596154Schristos #define BUFMAX 2048
99*48596154Schristos
100*48596154Schristos static int initialized = 0; /* !0 means we've been initialized */
101*48596154Schristos
102*48596154Schristos static void set_mem_fault_trap();
103*48596154Schristos
104*48596154Schristos static const char hexchars[]="0123456789abcdef";
105*48596154Schristos
106*48596154Schristos #define NUMREGS 72
107*48596154Schristos
108*48596154Schristos /* Number of bytes of registers. */
109*48596154Schristos #define NUMREGBYTES (NUMREGS * 4)
110*48596154Schristos enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
111*48596154Schristos O0, O1, O2, O3, O4, O5, SP, O7,
112*48596154Schristos L0, L1, L2, L3, L4, L5, L6, L7,
113*48596154Schristos I0, I1, I2, I3, I4, I5, FP, I7,
114*48596154Schristos
115*48596154Schristos F0, F1, F2, F3, F4, F5, F6, F7,
116*48596154Schristos F8, F9, F10, F11, F12, F13, F14, F15,
117*48596154Schristos F16, F17, F18, F19, F20, F21, F22, F23,
118*48596154Schristos F24, F25, F26, F27, F28, F29, F30, F31,
119*48596154Schristos Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
120*48596154Schristos
121*48596154Schristos /*************************** ASSEMBLY CODE MACROS *************************/
122*48596154Schristos /* */
123*48596154Schristos
124*48596154Schristos extern void trap_low();
125*48596154Schristos
126*48596154Schristos asm("
127*48596154Schristos .reserve trapstack, 1000 * 4, \"bss\", 8
128*48596154Schristos
129*48596154Schristos .data
130*48596154Schristos .align 4
131*48596154Schristos
132*48596154Schristos in_trap_handler:
133*48596154Schristos .word 0
134*48596154Schristos
135*48596154Schristos .text
136*48596154Schristos .align 4
137*48596154Schristos
138*48596154Schristos ! This function is called when any SPARC trap (except window overflow or
139*48596154Schristos ! underflow) occurs. It makes sure that the invalid register window is still
140*48596154Schristos ! available before jumping into C code. It will also restore the world if you
141*48596154Schristos ! return from handle_exception.
142*48596154Schristos
143*48596154Schristos .globl _trap_low
144*48596154Schristos _trap_low:
145*48596154Schristos mov %psr, %l0
146*48596154Schristos mov %wim, %l3
147*48596154Schristos
148*48596154Schristos srl %l3, %l0, %l4 ! wim >> cwp
149*48596154Schristos cmp %l4, 1
150*48596154Schristos bne window_fine ! Branch if not in the invalid window
151*48596154Schristos nop
152*48596154Schristos
153*48596154Schristos ! Handle window overflow
154*48596154Schristos
155*48596154Schristos mov %g1, %l4 ! Save g1, we use it to hold the wim
156*48596154Schristos srl %l3, 1, %g1 ! Rotate wim right
157*48596154Schristos tst %g1
158*48596154Schristos bg good_wim ! Branch if new wim is non-zero
159*48596154Schristos nop
160*48596154Schristos
161*48596154Schristos ! At this point, we need to bring a 1 into the high order bit of the wim.
162*48596154Schristos ! Since we don't want to make any assumptions about the number of register
163*48596154Schristos ! windows, we figure it out dynamically so as to setup the wim correctly.
164*48596154Schristos
165*48596154Schristos not %g1 ! Fill g1 with ones
166*48596154Schristos mov %g1, %wim ! Fill the wim with ones
167*48596154Schristos nop
168*48596154Schristos nop
169*48596154Schristos nop
170*48596154Schristos mov %wim, %g1 ! Read back the wim
171*48596154Schristos inc %g1 ! Now g1 has 1 just to left of wim
172*48596154Schristos srl %g1, 1, %g1 ! Now put 1 at top of wim
173*48596154Schristos mov %g0, %wim ! Clear wim so that subsequent save
174*48596154Schristos nop ! won't trap
175*48596154Schristos nop
176*48596154Schristos nop
177*48596154Schristos
178*48596154Schristos good_wim:
179*48596154Schristos save %g0, %g0, %g0 ! Slip into next window
180*48596154Schristos mov %g1, %wim ! Install the new wim
181*48596154Schristos
182*48596154Schristos std %l0, [%sp + 0 * 4] ! save L & I registers
183*48596154Schristos std %l2, [%sp + 2 * 4]
184*48596154Schristos std %l4, [%sp + 4 * 4]
185*48596154Schristos std %l6, [%sp + 6 * 4]
186*48596154Schristos
187*48596154Schristos std %i0, [%sp + 8 * 4]
188*48596154Schristos std %i2, [%sp + 10 * 4]
189*48596154Schristos std %i4, [%sp + 12 * 4]
190*48596154Schristos std %i6, [%sp + 14 * 4]
191*48596154Schristos
192*48596154Schristos restore ! Go back to trap window.
193*48596154Schristos mov %l4, %g1 ! Restore %g1
194*48596154Schristos
195*48596154Schristos window_fine:
196*48596154Schristos sethi %hi(in_trap_handler), %l4
197*48596154Schristos ld [%lo(in_trap_handler) + %l4], %l5
198*48596154Schristos tst %l5
199*48596154Schristos bg recursive_trap
200*48596154Schristos inc %l5
201*48596154Schristos
202*48596154Schristos set trapstack+1000*4, %sp ! Switch to trap stack
203*48596154Schristos
204*48596154Schristos recursive_trap:
205*48596154Schristos st %l5, [%lo(in_trap_handler) + %l4]
206*48596154Schristos sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
207*48596154Schristos ! + hidden arg + arg spill
208*48596154Schristos ! + doubleword alignment
209*48596154Schristos ! + registers[72] local var
210*48596154Schristos
211*48596154Schristos std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
212*48596154Schristos std %g2, [%sp + (24 + 2) * 4]
213*48596154Schristos std %g4, [%sp + (24 + 4) * 4]
214*48596154Schristos std %g6, [%sp + (24 + 6) * 4]
215*48596154Schristos
216*48596154Schristos std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
217*48596154Schristos std %i2, [%sp + (24 + 10) * 4]
218*48596154Schristos std %i4, [%sp + (24 + 12) * 4]
219*48596154Schristos std %i6, [%sp + (24 + 14) * 4]
220*48596154Schristos ! F0->F31 not implemented
221*48596154Schristos mov %y, %l4
222*48596154Schristos mov %tbr, %l5
223*48596154Schristos st %l4, [%sp + (24 + 64) * 4] ! Y
224*48596154Schristos st %l0, [%sp + (24 + 65) * 4] ! PSR
225*48596154Schristos st %l3, [%sp + (24 + 66) * 4] ! WIM
226*48596154Schristos st %l5, [%sp + (24 + 67) * 4] ! TBR
227*48596154Schristos st %l1, [%sp + (24 + 68) * 4] ! PC
228*48596154Schristos st %l2, [%sp + (24 + 69) * 4] ! NPC
229*48596154Schristos
230*48596154Schristos ! CPSR and FPSR not impl
231*48596154Schristos
232*48596154Schristos or %l0, 0xf20, %l4
233*48596154Schristos mov %l4, %psr ! Turn on traps, disable interrupts
234*48596154Schristos
235*48596154Schristos call _handle_exception
236*48596154Schristos add %sp, 24 * 4, %o0 ! Pass address of registers
237*48596154Schristos
238*48596154Schristos ! Reload all of the registers that aren't on the stack
239*48596154Schristos
240*48596154Schristos ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
241*48596154Schristos ldd [%sp + (24 + 2) * 4], %g2
242*48596154Schristos ldd [%sp + (24 + 4) * 4], %g4
243*48596154Schristos ldd [%sp + (24 + 6) * 4], %g6
244*48596154Schristos
245*48596154Schristos ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
246*48596154Schristos ldd [%sp + (24 + 10) * 4], %i2
247*48596154Schristos ldd [%sp + (24 + 12) * 4], %i4
248*48596154Schristos ldd [%sp + (24 + 14) * 4], %i6
249*48596154Schristos
250*48596154Schristos ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
251*48596154Schristos ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
252*48596154Schristos
253*48596154Schristos restore ! Ensure that previous window is valid
254*48596154Schristos save %g0, %g0, %g0 ! by causing a window_underflow trap
255*48596154Schristos
256*48596154Schristos mov %l0, %y
257*48596154Schristos mov %l1, %psr ! Make sure that traps are disabled
258*48596154Schristos ! for rett
259*48596154Schristos
260*48596154Schristos sethi %hi(in_trap_handler), %l4
261*48596154Schristos ld [%lo(in_trap_handler) + %l4], %l5
262*48596154Schristos dec %l5
263*48596154Schristos st %l5, [%lo(in_trap_handler) + %l4]
264*48596154Schristos
265*48596154Schristos jmpl %l2, %g0 ! Restore old PC
266*48596154Schristos rett %l3 ! Restore old nPC
267*48596154Schristos ");
268*48596154Schristos
269*48596154Schristos /* Convert ch from a hex digit to an int */
270*48596154Schristos
271*48596154Schristos static int
hex(unsigned char ch)272*48596154Schristos hex (unsigned char ch)
273*48596154Schristos {
274*48596154Schristos if (ch >= 'a' && ch <= 'f')
275*48596154Schristos return ch-'a'+10;
276*48596154Schristos if (ch >= '0' && ch <= '9')
277*48596154Schristos return ch-'0';
278*48596154Schristos if (ch >= 'A' && ch <= 'F')
279*48596154Schristos return ch-'A'+10;
280*48596154Schristos return -1;
281*48596154Schristos }
282*48596154Schristos
283*48596154Schristos static char remcomInBuffer[BUFMAX];
284*48596154Schristos static char remcomOutBuffer[BUFMAX];
285*48596154Schristos
286*48596154Schristos /* scan for the sequence $<data>#<checksum> */
287*48596154Schristos
288*48596154Schristos unsigned char *
getpacket(void)289*48596154Schristos getpacket (void)
290*48596154Schristos {
291*48596154Schristos unsigned char *buffer = &remcomInBuffer[0];
292*48596154Schristos unsigned char checksum;
293*48596154Schristos unsigned char xmitcsum;
294*48596154Schristos int count;
295*48596154Schristos char ch;
296*48596154Schristos
297*48596154Schristos while (1)
298*48596154Schristos {
299*48596154Schristos /* wait around for the start character, ignore all other characters */
300*48596154Schristos while ((ch = getDebugChar ()) != '$')
301*48596154Schristos ;
302*48596154Schristos
303*48596154Schristos retry:
304*48596154Schristos checksum = 0;
305*48596154Schristos xmitcsum = -1;
306*48596154Schristos count = 0;
307*48596154Schristos
308*48596154Schristos /* now, read until a # or end of buffer is found */
309*48596154Schristos while (count < BUFMAX - 1)
310*48596154Schristos {
311*48596154Schristos ch = getDebugChar ();
312*48596154Schristos if (ch == '$')
313*48596154Schristos goto retry;
314*48596154Schristos if (ch == '#')
315*48596154Schristos break;
316*48596154Schristos checksum = checksum + ch;
317*48596154Schristos buffer[count] = ch;
318*48596154Schristos count = count + 1;
319*48596154Schristos }
320*48596154Schristos buffer[count] = 0;
321*48596154Schristos
322*48596154Schristos if (ch == '#')
323*48596154Schristos {
324*48596154Schristos ch = getDebugChar ();
325*48596154Schristos xmitcsum = hex (ch) << 4;
326*48596154Schristos ch = getDebugChar ();
327*48596154Schristos xmitcsum += hex (ch);
328*48596154Schristos
329*48596154Schristos if (checksum != xmitcsum)
330*48596154Schristos {
331*48596154Schristos putDebugChar ('-'); /* failed checksum */
332*48596154Schristos }
333*48596154Schristos else
334*48596154Schristos {
335*48596154Schristos putDebugChar ('+'); /* successful transfer */
336*48596154Schristos
337*48596154Schristos /* if a sequence char is present, reply the sequence ID */
338*48596154Schristos if (buffer[2] == ':')
339*48596154Schristos {
340*48596154Schristos putDebugChar (buffer[0]);
341*48596154Schristos putDebugChar (buffer[1]);
342*48596154Schristos
343*48596154Schristos return &buffer[3];
344*48596154Schristos }
345*48596154Schristos
346*48596154Schristos return &buffer[0];
347*48596154Schristos }
348*48596154Schristos }
349*48596154Schristos }
350*48596154Schristos }
351*48596154Schristos
352*48596154Schristos /* send the packet in buffer. */
353*48596154Schristos
354*48596154Schristos static void
putpacket(unsigned char * buffer)355*48596154Schristos putpacket (unsigned char *buffer)
356*48596154Schristos {
357*48596154Schristos unsigned char checksum;
358*48596154Schristos int count;
359*48596154Schristos unsigned char ch;
360*48596154Schristos
361*48596154Schristos /* $<packet info>#<checksum>. */
362*48596154Schristos do
363*48596154Schristos {
364*48596154Schristos putDebugChar('$');
365*48596154Schristos checksum = 0;
366*48596154Schristos count = 0;
367*48596154Schristos
368*48596154Schristos while (ch = buffer[count])
369*48596154Schristos {
370*48596154Schristos putDebugChar(ch);
371*48596154Schristos checksum += ch;
372*48596154Schristos count += 1;
373*48596154Schristos }
374*48596154Schristos
375*48596154Schristos putDebugChar('#');
376*48596154Schristos putDebugChar(hexchars[checksum >> 4]);
377*48596154Schristos putDebugChar(hexchars[checksum & 0xf]);
378*48596154Schristos
379*48596154Schristos }
380*48596154Schristos while (getDebugChar() != '+');
381*48596154Schristos }
382*48596154Schristos
383*48596154Schristos /* Indicate to caller of mem2hex or hex2mem that there has been an
384*48596154Schristos error. */
385*48596154Schristos static volatile int mem_err = 0;
386*48596154Schristos
387*48596154Schristos /* Convert the memory pointed to by mem into hex, placing result in buf.
388*48596154Schristos * Return a pointer to the last char put in buf (null), in case of mem fault,
389*48596154Schristos * return 0.
390*48596154Schristos * If MAY_FAULT is non-zero, then we will handle memory faults by returning
391*48596154Schristos * a 0, else treat a fault like any other fault in the stub.
392*48596154Schristos */
393*48596154Schristos
394*48596154Schristos static unsigned char *
mem2hex(unsigned char * mem,unsigned char * buf,int count,int may_fault)395*48596154Schristos mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
396*48596154Schristos {
397*48596154Schristos unsigned char ch;
398*48596154Schristos
399*48596154Schristos set_mem_fault_trap(may_fault);
400*48596154Schristos
401*48596154Schristos while (count-- > 0)
402*48596154Schristos {
403*48596154Schristos ch = *mem++;
404*48596154Schristos if (mem_err)
405*48596154Schristos return 0;
406*48596154Schristos *buf++ = hexchars[ch >> 4];
407*48596154Schristos *buf++ = hexchars[ch & 0xf];
408*48596154Schristos }
409*48596154Schristos
410*48596154Schristos *buf = 0;
411*48596154Schristos
412*48596154Schristos set_mem_fault_trap(0);
413*48596154Schristos
414*48596154Schristos return buf;
415*48596154Schristos }
416*48596154Schristos
417*48596154Schristos /* convert the hex array pointed to by buf into binary to be placed in mem
418*48596154Schristos * return a pointer to the character AFTER the last byte written */
419*48596154Schristos
420*48596154Schristos static char *
hex2mem(unsigned char * buf,unsigned char * mem,int count,int may_fault)421*48596154Schristos hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
422*48596154Schristos {
423*48596154Schristos int i;
424*48596154Schristos unsigned char ch;
425*48596154Schristos
426*48596154Schristos set_mem_fault_trap(may_fault);
427*48596154Schristos
428*48596154Schristos for (i=0; i<count; i++)
429*48596154Schristos {
430*48596154Schristos ch = hex(*buf++) << 4;
431*48596154Schristos ch |= hex(*buf++);
432*48596154Schristos *mem++ = ch;
433*48596154Schristos if (mem_err)
434*48596154Schristos return 0;
435*48596154Schristos }
436*48596154Schristos
437*48596154Schristos set_mem_fault_trap(0);
438*48596154Schristos
439*48596154Schristos return mem;
440*48596154Schristos }
441*48596154Schristos
442*48596154Schristos /* This table contains the mapping between SPARC hardware trap types, and
443*48596154Schristos signals, which are primarily what GDB understands. It also indicates
444*48596154Schristos which hardware traps we need to commandeer when initializing the stub. */
445*48596154Schristos
446*48596154Schristos static struct hard_trap_info
447*48596154Schristos {
448*48596154Schristos unsigned char tt; /* Trap type code for SPARClite */
449*48596154Schristos unsigned char signo; /* Signal that we map this trap into */
450*48596154Schristos } hard_trap_info[] = {
451*48596154Schristos {1, SIGSEGV}, /* instruction access error */
452*48596154Schristos {2, SIGILL}, /* privileged instruction */
453*48596154Schristos {3, SIGILL}, /* illegal instruction */
454*48596154Schristos {4, SIGEMT}, /* fp disabled */
455*48596154Schristos {36, SIGEMT}, /* cp disabled */
456*48596154Schristos {7, SIGBUS}, /* mem address not aligned */
457*48596154Schristos {9, SIGSEGV}, /* data access exception */
458*48596154Schristos {10, SIGEMT}, /* tag overflow */
459*48596154Schristos {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
460*48596154Schristos {0, 0} /* Must be last */
461*48596154Schristos };
462*48596154Schristos
463*48596154Schristos /* Set up exception handlers for tracing and breakpoints */
464*48596154Schristos
465*48596154Schristos void
set_debug_traps(void)466*48596154Schristos set_debug_traps (void)
467*48596154Schristos {
468*48596154Schristos struct hard_trap_info *ht;
469*48596154Schristos
470*48596154Schristos for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
471*48596154Schristos exceptionHandler(ht->tt, trap_low);
472*48596154Schristos
473*48596154Schristos initialized = 1;
474*48596154Schristos }
475*48596154Schristos
476*48596154Schristos asm ("
477*48596154Schristos ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
478*48596154Schristos ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
479*48596154Schristos ! 0 would ever contain code that could mem fault. This routine will skip
480*48596154Schristos ! past the faulting instruction after setting mem_err.
481*48596154Schristos
482*48596154Schristos .text
483*48596154Schristos .align 4
484*48596154Schristos
485*48596154Schristos _fltr_set_mem_err:
486*48596154Schristos sethi %hi(_mem_err), %l0
487*48596154Schristos st %l1, [%l0 + %lo(_mem_err)]
488*48596154Schristos jmpl %l2, %g0
489*48596154Schristos rett %l2+4
490*48596154Schristos ");
491*48596154Schristos
492*48596154Schristos static void
set_mem_fault_trap(int enable)493*48596154Schristos set_mem_fault_trap (int enable)
494*48596154Schristos {
495*48596154Schristos extern void fltr_set_mem_err();
496*48596154Schristos mem_err = 0;
497*48596154Schristos
498*48596154Schristos if (enable)
499*48596154Schristos exceptionHandler(9, fltr_set_mem_err);
500*48596154Schristos else
501*48596154Schristos exceptionHandler(9, trap_low);
502*48596154Schristos }
503*48596154Schristos
504*48596154Schristos /* Convert the SPARC hardware trap type code to a unix signal number. */
505*48596154Schristos
506*48596154Schristos static int
computeSignal(int tt)507*48596154Schristos computeSignal (int tt)
508*48596154Schristos {
509*48596154Schristos struct hard_trap_info *ht;
510*48596154Schristos
511*48596154Schristos for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
512*48596154Schristos if (ht->tt == tt)
513*48596154Schristos return ht->signo;
514*48596154Schristos
515*48596154Schristos return SIGHUP; /* default for things we don't know about */
516*48596154Schristos }
517*48596154Schristos
518*48596154Schristos /*
519*48596154Schristos * While we find nice hex chars, build an int.
520*48596154Schristos * Return number of chars processed.
521*48596154Schristos */
522*48596154Schristos
523*48596154Schristos static int
hexToInt(char ** ptr,int * intValue)524*48596154Schristos hexToInt(char **ptr, int *intValue)
525*48596154Schristos {
526*48596154Schristos int numChars = 0;
527*48596154Schristos int hexValue;
528*48596154Schristos
529*48596154Schristos *intValue = 0;
530*48596154Schristos
531*48596154Schristos while (**ptr)
532*48596154Schristos {
533*48596154Schristos hexValue = hex(**ptr);
534*48596154Schristos if (hexValue < 0)
535*48596154Schristos break;
536*48596154Schristos
537*48596154Schristos *intValue = (*intValue << 4) | hexValue;
538*48596154Schristos numChars ++;
539*48596154Schristos
540*48596154Schristos (*ptr)++;
541*48596154Schristos }
542*48596154Schristos
543*48596154Schristos return (numChars);
544*48596154Schristos }
545*48596154Schristos
546*48596154Schristos /*
547*48596154Schristos * This function does all command procesing for interfacing to gdb. It
548*48596154Schristos * returns 1 if you should skip the instruction at the trap address, 0
549*48596154Schristos * otherwise.
550*48596154Schristos */
551*48596154Schristos
552*48596154Schristos extern void breakinst();
553*48596154Schristos
554*48596154Schristos static void
handle_exception(unsigned long * registers)555*48596154Schristos handle_exception (unsigned long *registers)
556*48596154Schristos {
557*48596154Schristos int tt; /* Trap type */
558*48596154Schristos int sigval;
559*48596154Schristos int addr;
560*48596154Schristos int length;
561*48596154Schristos char *ptr;
562*48596154Schristos unsigned long *sp;
563*48596154Schristos
564*48596154Schristos /* First, we must force all of the windows to be spilled out */
565*48596154Schristos
566*48596154Schristos asm(" save %sp, -64, %sp
567*48596154Schristos save %sp, -64, %sp
568*48596154Schristos save %sp, -64, %sp
569*48596154Schristos save %sp, -64, %sp
570*48596154Schristos save %sp, -64, %sp
571*48596154Schristos save %sp, -64, %sp
572*48596154Schristos save %sp, -64, %sp
573*48596154Schristos save %sp, -64, %sp
574*48596154Schristos restore
575*48596154Schristos restore
576*48596154Schristos restore
577*48596154Schristos restore
578*48596154Schristos restore
579*48596154Schristos restore
580*48596154Schristos restore
581*48596154Schristos restore
582*48596154Schristos ");
583*48596154Schristos
584*48596154Schristos if (registers[PC] == (unsigned long)breakinst)
585*48596154Schristos {
586*48596154Schristos registers[PC] = registers[NPC];
587*48596154Schristos registers[NPC] += 4;
588*48596154Schristos }
589*48596154Schristos
590*48596154Schristos sp = (unsigned long *)registers[SP];
591*48596154Schristos
592*48596154Schristos tt = (registers[TBR] >> 4) & 0xff;
593*48596154Schristos
594*48596154Schristos /* reply to host that an exception has occurred */
595*48596154Schristos sigval = computeSignal(tt);
596*48596154Schristos ptr = remcomOutBuffer;
597*48596154Schristos
598*48596154Schristos *ptr++ = 'T';
599*48596154Schristos *ptr++ = hexchars[sigval >> 4];
600*48596154Schristos *ptr++ = hexchars[sigval & 0xf];
601*48596154Schristos
602*48596154Schristos *ptr++ = hexchars[PC >> 4];
603*48596154Schristos *ptr++ = hexchars[PC & 0xf];
604*48596154Schristos *ptr++ = ':';
605*48596154Schristos ptr = mem2hex((char *)®isters[PC], ptr, 4, 0);
606*48596154Schristos *ptr++ = ';';
607*48596154Schristos
608*48596154Schristos *ptr++ = hexchars[FP >> 4];
609*48596154Schristos *ptr++ = hexchars[FP & 0xf];
610*48596154Schristos *ptr++ = ':';
611*48596154Schristos ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
612*48596154Schristos *ptr++ = ';';
613*48596154Schristos
614*48596154Schristos *ptr++ = hexchars[SP >> 4];
615*48596154Schristos *ptr++ = hexchars[SP & 0xf];
616*48596154Schristos *ptr++ = ':';
617*48596154Schristos ptr = mem2hex((char *)&sp, ptr, 4, 0);
618*48596154Schristos *ptr++ = ';';
619*48596154Schristos
620*48596154Schristos *ptr++ = hexchars[NPC >> 4];
621*48596154Schristos *ptr++ = hexchars[NPC & 0xf];
622*48596154Schristos *ptr++ = ':';
623*48596154Schristos ptr = mem2hex((char *)®isters[NPC], ptr, 4, 0);
624*48596154Schristos *ptr++ = ';';
625*48596154Schristos
626*48596154Schristos *ptr++ = hexchars[O7 >> 4];
627*48596154Schristos *ptr++ = hexchars[O7 & 0xf];
628*48596154Schristos *ptr++ = ':';
629*48596154Schristos ptr = mem2hex((char *)®isters[O7], ptr, 4, 0);
630*48596154Schristos *ptr++ = ';';
631*48596154Schristos
632*48596154Schristos *ptr++ = 0;
633*48596154Schristos
634*48596154Schristos putpacket(remcomOutBuffer);
635*48596154Schristos
636*48596154Schristos while (1)
637*48596154Schristos {
638*48596154Schristos remcomOutBuffer[0] = 0;
639*48596154Schristos
640*48596154Schristos ptr = getpacket();
641*48596154Schristos switch (*ptr++)
642*48596154Schristos {
643*48596154Schristos case '?':
644*48596154Schristos remcomOutBuffer[0] = 'S';
645*48596154Schristos remcomOutBuffer[1] = hexchars[sigval >> 4];
646*48596154Schristos remcomOutBuffer[2] = hexchars[sigval & 0xf];
647*48596154Schristos remcomOutBuffer[3] = 0;
648*48596154Schristos break;
649*48596154Schristos
650*48596154Schristos case 'd': /* toggle debug flag */
651*48596154Schristos break;
652*48596154Schristos
653*48596154Schristos case 'g': /* return the value of the CPU registers */
654*48596154Schristos {
655*48596154Schristos ptr = remcomOutBuffer;
656*48596154Schristos ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
657*48596154Schristos ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
658*48596154Schristos memset(ptr, '0', 32 * 8); /* Floating point */
659*48596154Schristos mem2hex((char *)®isters[Y],
660*48596154Schristos ptr + 32 * 4 * 2,
661*48596154Schristos 8 * 4,
662*48596154Schristos 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
663*48596154Schristos }
664*48596154Schristos break;
665*48596154Schristos
666*48596154Schristos case 'G': /* set the value of the CPU registers - return OK */
667*48596154Schristos {
668*48596154Schristos unsigned long *newsp, psr;
669*48596154Schristos
670*48596154Schristos psr = registers[PSR];
671*48596154Schristos
672*48596154Schristos hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
673*48596154Schristos hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
674*48596154Schristos hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y],
675*48596154Schristos 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
676*48596154Schristos
677*48596154Schristos /* See if the stack pointer has moved. If so, then copy the saved
678*48596154Schristos locals and ins to the new location. This keeps the window
679*48596154Schristos overflow and underflow routines happy. */
680*48596154Schristos
681*48596154Schristos newsp = (unsigned long *)registers[SP];
682*48596154Schristos if (sp != newsp)
683*48596154Schristos sp = memcpy(newsp, sp, 16 * 4);
684*48596154Schristos
685*48596154Schristos /* Don't allow CWP to be modified. */
686*48596154Schristos
687*48596154Schristos if (psr != registers[PSR])
688*48596154Schristos registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
689*48596154Schristos
690*48596154Schristos strcpy(remcomOutBuffer,"OK");
691*48596154Schristos }
692*48596154Schristos break;
693*48596154Schristos
694*48596154Schristos case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
695*48596154Schristos /* Try to read %x,%x. */
696*48596154Schristos
697*48596154Schristos if (hexToInt(&ptr, &addr)
698*48596154Schristos && *ptr++ == ','
699*48596154Schristos && hexToInt(&ptr, &length))
700*48596154Schristos {
701*48596154Schristos if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
702*48596154Schristos break;
703*48596154Schristos
704*48596154Schristos strcpy (remcomOutBuffer, "E03");
705*48596154Schristos }
706*48596154Schristos else
707*48596154Schristos strcpy(remcomOutBuffer,"E01");
708*48596154Schristos break;
709*48596154Schristos
710*48596154Schristos case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
711*48596154Schristos /* Try to read '%x,%x:'. */
712*48596154Schristos
713*48596154Schristos if (hexToInt(&ptr, &addr)
714*48596154Schristos && *ptr++ == ','
715*48596154Schristos && hexToInt(&ptr, &length)
716*48596154Schristos && *ptr++ == ':')
717*48596154Schristos {
718*48596154Schristos if (hex2mem(ptr, (char *)addr, length, 1))
719*48596154Schristos strcpy(remcomOutBuffer, "OK");
720*48596154Schristos else
721*48596154Schristos strcpy(remcomOutBuffer, "E03");
722*48596154Schristos }
723*48596154Schristos else
724*48596154Schristos strcpy(remcomOutBuffer, "E02");
725*48596154Schristos break;
726*48596154Schristos
727*48596154Schristos case 'c': /* cAA..AA Continue at address AA..AA(optional) */
728*48596154Schristos /* try to read optional parameter, pc unchanged if no parm */
729*48596154Schristos
730*48596154Schristos if (hexToInt(&ptr, &addr))
731*48596154Schristos {
732*48596154Schristos registers[PC] = addr;
733*48596154Schristos registers[NPC] = addr + 4;
734*48596154Schristos }
735*48596154Schristos
736*48596154Schristos /* Need to flush the instruction cache here, as we may have deposited a
737*48596154Schristos breakpoint, and the icache probably has no way of knowing that a data ref to
738*48596154Schristos some location may have changed something that is in the instruction cache.
739*48596154Schristos */
740*48596154Schristos
741*48596154Schristos flush_i_cache();
742*48596154Schristos return;
743*48596154Schristos
744*48596154Schristos /* kill the program */
745*48596154Schristos case 'k' : /* do nothing */
746*48596154Schristos break;
747*48596154Schristos #if 0
748*48596154Schristos case 't': /* Test feature */
749*48596154Schristos asm (" std %f30,[%sp]");
750*48596154Schristos break;
751*48596154Schristos #endif
752*48596154Schristos case 'r': /* Reset */
753*48596154Schristos asm ("call 0
754*48596154Schristos nop ");
755*48596154Schristos break;
756*48596154Schristos } /* switch */
757*48596154Schristos
758*48596154Schristos /* reply to the request */
759*48596154Schristos putpacket(remcomOutBuffer);
760*48596154Schristos }
761*48596154Schristos }
762*48596154Schristos
763*48596154Schristos /* This function will generate a breakpoint exception. It is used at the
764*48596154Schristos beginning of a program to sync up with a debugger and can be used
765*48596154Schristos otherwise as a quick means to stop program execution and "break" into
766*48596154Schristos the debugger. */
767*48596154Schristos
768*48596154Schristos void
breakpoint(void)769*48596154Schristos breakpoint (void)
770*48596154Schristos {
771*48596154Schristos if (!initialized)
772*48596154Schristos return;
773*48596154Schristos
774*48596154Schristos asm(" .globl _breakinst
775*48596154Schristos
776*48596154Schristos _breakinst: ta 1
777*48596154Schristos ");
778*48596154Schristos }
779