#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/cons.h>
#include <ddb/ddb.h>
#include <machine/setjmp.h>
void gdb_handle_exception (db_regs_t *, int, int);
extern jmp_buf db_jmpbuf;
#define BUFMAX 400
#define strlen gdb_strlen
#define strcpy gdb_strcpy
static int
strlen (const char *s)
{
const char *s1 = s;
while (*s1++ != '\000');
return s1 - s;
}
static char *
strcpy (char *dst, const char *src)
{
char *retval = dst;
while ((*dst++ = *src++) != '\000');
return retval;
}
static int
putDebugChar (int c)
{
if (gdb_tab == NULL)
return 0;
gdb_tab->cn_putc(gdb_tab->cn_gdbprivate, c);
return 1;
}
static int
getDebugChar (void)
{
if (gdb_tab == NULL)
return -1;
return gdb_tab->cn_getc(gdb_tab->cn_gdbprivate);
}
static const char hexchars[]="0123456789abcdef";
static int
hex(char ch)
{
if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
if ((ch >= '0') && (ch <= '9')) return (ch-'0');
if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
return (-1);
}
static void
getpacket (char *buffer)
{
unsigned char checksum;
unsigned char xmitcsum;
int i;
int count;
unsigned char ch;
do
{
while ((ch = (getDebugChar () & 0x7f)) != '$');
checksum = 0;
xmitcsum = -1;
count = 0;
while (count < BUFMAX - 1)
{
ch = getDebugChar () & 0x7f;
if (ch == '#')
break;
checksum = checksum + ch;
buffer[count] = ch;
count = count + 1;
}
buffer[count] = 0;
if (ch == '#')
{
xmitcsum = hex (getDebugChar () & 0x7f) << 4;
xmitcsum += hex (getDebugChar () & 0x7f);
if (checksum != xmitcsum)
putDebugChar ('-');
else
{
putDebugChar ('+');
if (buffer[2] == ':')
{
putDebugChar (buffer[0]);
putDebugChar (buffer[1]);
count = strlen (buffer);
for (i=3; i <= count; i++)
buffer[i-3] = buffer[i];
}
}
}
}
while (checksum != xmitcsum);
}
static void
putpacket (char *buffer)
{
unsigned char checksum;
int count;
unsigned char ch;
do
{
#ifdef GDB_REMOTE_CHAT
putDebugChar ('|');
putDebugChar ('|');
putDebugChar ('|');
putDebugChar ('|');
#endif
putDebugChar ('$');
checksum = 0;
count = 0;
while ((ch=buffer[count]) != 0)
{
putDebugChar (ch);
checksum += ch;
count += 1;
}
putDebugChar ('#');
putDebugChar (hexchars[checksum >> 4]);
putDebugChar (hexchars[checksum & 0xf]);
}
while ((getDebugChar () & 0x7f) != '+');
}
static char remcomInBuffer[BUFMAX];
static char remcomOutBuffer[BUFMAX];
static int
get_char (vm_offset_t addr)
{
char data;
if (setjmp (db_jmpbuf))
return -1;
db_read_bytes (addr, 1, &data);
return data & 0xff;
}
static int
set_char (vm_offset_t addr, int val)
{
char data;
if (setjmp (db_jmpbuf))
return -1;
data = val;
db_write_bytes (addr, 1, &data);
return 0;
}
static char *
mem2hex (vm_offset_t mem, char *buf, int count)
{
int i;
int ch;
for (i=0;i<count;i++) {
ch = get_char (mem++);
if (ch == -1)
return NULL;
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
return(buf);
}
static char *
hex2mem (char *buf, vm_offset_t mem, int count)
{
int i;
int ch;
int rv;
for (i=0;i<count;i++) {
ch = hex(*buf++) << 4;
ch = ch + hex(*buf++);
rv = set_char (mem++, ch);
if (rv == -1)
return NULL;
}
return(buf);
}
static int
computeSignal (int exceptionVector)
{
int sigval;
switch (exceptionVector & ~T_USER)
{
case 0: sigval = 8; break;
case 1: sigval = 5; break;
case 3: sigval = 5; break;
case 4: sigval = 16; break;
case 5: sigval = 16; break;
case 6: sigval = 4; break;
case 7: sigval = 8; break;
case 8: sigval = 7; break;
case 9: sigval = 11; break;
case 10: sigval = 5; break;
case 11: sigval = 11; break;
case 12: sigval = 11; break;
case 13: sigval = 11; break;
case 14: sigval = 11; break;
case 16: sigval = 7; break;
default:
sigval = 7;
}
return (sigval);
}
static int
hexToInt(char **ptr, int *intValue)
{
int numChars = 0;
int hexValue;
*intValue = 0;
while (**ptr)
{
hexValue = hex(**ptr);
if (hexValue >=0)
{
*intValue = (*intValue <<4) | hexValue;
numChars ++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
static long
hexToLong(char **ptr, long *longValue)
{
int numChars = 0;
int hexValue;
*longValue = 0;
while (**ptr)
{
hexValue = hex(**ptr);
if (hexValue >=0)
{
*longValue = (*longValue <<4) | hexValue;
numChars ++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
#define NUMREGBYTES (sizeof registers)
#define PC 16
#define SP 7
#define FP 6
#define NUM_REGS 22
void
gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
{
int sigval;
long addr;
int length;
char * ptr;
struct x86_64regs {
unsigned long rax;
unsigned long rbx;
unsigned long rcx;
unsigned long rdx;
unsigned long rsi;
unsigned long rdi;
unsigned long rbp;
unsigned long rsp;
unsigned long r8;
unsigned long r9;
unsigned long r10;
unsigned long r11;
unsigned long r12;
unsigned long r13;
unsigned long r14;
unsigned long r15;
unsigned long rip;
unsigned long rflags;
unsigned int cs;
unsigned int ss;
};
struct x86_64regs registers;
registers.rax = raw_regs->tf_rax;
registers.rbx = raw_regs->tf_rbx;
registers.rcx = raw_regs->tf_rcx;
registers.rdx = raw_regs->tf_rdx;
registers.rsp = raw_regs->tf_rsp;
registers.rbp = raw_regs->tf_rbp;
registers.rsi = raw_regs->tf_rsi;
registers.rdi = raw_regs->tf_rdi;
registers.r8 = raw_regs->tf_r8;
registers.r9 = raw_regs->tf_r9;
registers.r10 = raw_regs->tf_r10;
registers.r11 = raw_regs->tf_r11;
registers.r12 = raw_regs->tf_r12;
registers.r13 = raw_regs->tf_r13;
registers.r14 = raw_regs->tf_r14;
registers.r15 = raw_regs->tf_r15;
registers.rip = raw_regs->tf_rip;
registers.rflags = raw_regs->tf_rflags;
registers.cs = raw_regs->tf_cs;
registers.ss = raw_regs->tf_ss;
sigval = computeSignal (type);
ptr = remcomOutBuffer;
*ptr++ = 'T';
*ptr++ = hexchars[sigval >> 4];
*ptr++ = hexchars[sigval & 0xf];
*ptr++ = hexchars[PC >> 4];
*ptr++ = hexchars[PC & 0xf];
*ptr++ = ':';
ptr = mem2hex ((vm_offset_t)®isters.rip, ptr, 8);
*ptr++ = ';';
*ptr++ = hexchars[FP >> 4];
*ptr++ = hexchars[FP & 0xf];
*ptr++ = ':';
ptr = mem2hex ((vm_offset_t)®isters.rbp, ptr, 8);
*ptr++ = ';';
*ptr++ = hexchars[SP >> 4];
*ptr++ = hexchars[SP & 0xf];
*ptr++ = ':';
ptr = mem2hex ((vm_offset_t)®isters.rsp, ptr, 8);
*ptr++ = ';';
*ptr++ = 0;
putpacket (remcomOutBuffer);
while (1)
{
remcomOutBuffer[0] = 0;
getpacket (remcomInBuffer);
switch (remcomInBuffer[0])
{
case '?':
remcomOutBuffer[0] = 'S';
remcomOutBuffer[1] = hexchars[sigval >> 4];
remcomOutBuffer[2] = hexchars[sigval % 16];
remcomOutBuffer[3] = 0;
break;
case 'D':
putpacket(remcomOutBuffer);
boothowto &= ~RB_GDB;
return;
case 'g':
mem2hex ((vm_offset_t)®isters, remcomOutBuffer, NUMREGBYTES);
break;
case 'G':
hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, NUMREGBYTES);
strcpy (remcomOutBuffer, "OK");
break;
case 'P':
{
int regno;
ptr = &remcomInBuffer[1];
if (hexToInt (&ptr, ®no)
&& *ptr++ == '='
&& regno < NUM_REGS)
{
hex2mem (ptr, (vm_offset_t)®isters + regno * 8, 8);
strcpy(remcomOutBuffer,"OK");
}
else
strcpy (remcomOutBuffer, "P01");
break;
}
case 'm':
ptr = &remcomInBuffer[1];
if (hexToLong (&ptr, &addr)
&& *(ptr++) == ','
&& hexToInt (&ptr, &length))
{
if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL)
strcpy (remcomOutBuffer, "E03");
break;
}
else
strcpy (remcomOutBuffer, "E01");
break;
case 'M':
ptr = &remcomInBuffer[1];
if (hexToLong(&ptr,&addr)
&& *(ptr++) == ','
&& hexToInt(&ptr, &length)
&& *(ptr++) == ':')
{
if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL)
strcpy (remcomOutBuffer, "E03");
else
strcpy (remcomOutBuffer, "OK");
}
else
strcpy (remcomOutBuffer, "E02");
break;
case 'c' :
case 's' :
ptr = &remcomInBuffer[1];
if (hexToLong(&ptr,&addr))
registers.rip = addr;
if (remcomInBuffer[0] == 's')
registers.rflags |= PSL_T;
else
registers.rflags &= ~PSL_T;
raw_regs->tf_rax = registers.rax;
raw_regs->tf_rbx = registers.rbx;
raw_regs->tf_rcx = registers.rcx;
raw_regs->tf_rdx = registers.rdx;
raw_regs->tf_rsp = registers.rsp;
raw_regs->tf_rbp = registers.rbp;
raw_regs->tf_rsi = registers.rsi;
raw_regs->tf_rdi = registers.rdi;
raw_regs->tf_r8 = registers.r8;
raw_regs->tf_r9 = registers.r9;
raw_regs->tf_r10 = registers.r10;
raw_regs->tf_r11 = registers.r11;
raw_regs->tf_r12 = registers.r12;
raw_regs->tf_r13 = registers.r13;
raw_regs->tf_r14 = registers.r14;
raw_regs->tf_r15 = registers.r15;
raw_regs->tf_rip = registers.rip;
raw_regs->tf_rflags = registers.rflags;
raw_regs->tf_cs = registers.cs;
raw_regs->tf_ss = registers.ss;
return;
}
putpacket (remcomOutBuffer);
}
}