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 *)®isters[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 *)®isters[NPC], ptr, 4, 0); 62498944Sobrien *ptr++ = ';'; 62598944Sobrien 62698944Sobrien *ptr++ = hexchars[O7 >> 4]; 62798944Sobrien *ptr++ = hexchars[O7 & 0xf]; 62898944Sobrien *ptr++ = ':'; 62998944Sobrien ptr = mem2hex((char *)®isters[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 *)®isters[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 *)®isters[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