2006-10-26 21:27:04 +04:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2011-02-25 01:05:47 +03:00
|
|
|
|
// $Id$
|
2006-10-26 21:27:04 +04:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2020-12-08 22:52:39 +03:00
|
|
|
|
// Copyright (C) 2002-2020 The Bochs Project Team
|
2006-10-26 21:27:04 +04:00
|
|
|
|
//
|
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2009-12-04 23:02:12 +03:00
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2006-10-26 21:27:04 +04:00
|
|
|
|
|
2002-10-03 09:29:15 +04:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/types.h>
|
2012-03-11 22:12:50 +04:00
|
|
|
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#include <winsock2.h>
|
|
|
|
|
#define SIGTRAP 5
|
|
|
|
|
#else
|
2002-10-03 09:29:15 +04:00
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netinet/in.h>
|
2002-10-07 00:43:02 +04:00
|
|
|
|
#include <netinet/tcp.h>
|
2002-10-03 09:29:15 +04:00
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <signal.h>
|
2002-10-07 00:43:02 +04:00
|
|
|
|
#include <netdb.h>
|
2014-08-30 18:25:06 +04:00
|
|
|
|
#define closesocket(s) close(s)
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#endif
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
|
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
|
|
|
|
|
|
|
|
|
#include "bochs.h"
|
2010-02-26 17:18:19 +03:00
|
|
|
|
#include "param_names.h"
|
2006-04-25 19:59:20 +04:00
|
|
|
|
#include "cpu/cpu.h"
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
2006-10-26 21:27:04 +04:00
|
|
|
|
#define LOG_THIS gdbstublog->
|
2002-10-03 09:29:15 +04:00
|
|
|
|
#define IFDBG(x) x
|
|
|
|
|
|
|
|
|
|
static int last_stop_reason = GDBSTUB_STOP_NO_REASON;
|
|
|
|
|
|
|
|
|
|
#define GDBSTUB_EXECUTION_BREAKPOINT (0xac1)
|
|
|
|
|
#define GDBSTUB_TRACE (0xac2)
|
|
|
|
|
#define GDBSTUB_USER_BREAK (0xac3)
|
|
|
|
|
|
2006-03-04 15:43:47 +03:00
|
|
|
|
static bx_list_c *gdbstub_list;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
static int listen_socket_fd;
|
|
|
|
|
static int socket_fd;
|
2006-10-26 21:27:04 +04:00
|
|
|
|
static logfunctions *gdbstublog;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
|
|
|
|
static int hex(char ch)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
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 char buf[4096], *bufptr = buf;
|
|
|
|
|
|
|
|
|
|
static void flush_debug_buffer()
|
|
|
|
|
{
|
|
|
|
|
char *p = buf;
|
|
|
|
|
while (p != bufptr) {
|
|
|
|
|
int n = send(socket_fd, p, bufptr-p, 0);
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
BX_ERROR(("error on debug socket: %m"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
p += n;
|
|
|
|
|
}
|
|
|
|
|
bufptr = buf;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void put_debug_char(char ch)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (bufptr == buf + sizeof buf)
|
|
|
|
|
flush_debug_buffer();
|
|
|
|
|
*bufptr++ = ch;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char get_debug_char(void)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
|
|
recv(socket_fd, &ch, 1, 0);
|
|
|
|
|
|
|
|
|
|
return(ch);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char hexchars[]="0123456789abcdef";
|
|
|
|
|
|
2009-05-09 11:38:12 +04:00
|
|
|
|
static void put_reply(const char* buffer)
|
2002-10-03 09:29:15 +04:00
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
unsigned char csum;
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-08-16 16:29:30 +04:00
|
|
|
|
BX_DEBUG(("put_buffer '%s'", buffer));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
2008-02-06 01:57:43 +03:00
|
|
|
|
do {
|
2006-10-29 11:48:30 +03:00
|
|
|
|
put_debug_char('$');
|
|
|
|
|
|
|
|
|
|
csum = 0;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (buffer[i] != 0)
|
|
|
|
|
{
|
|
|
|
|
put_debug_char(buffer[i]);
|
|
|
|
|
csum = csum + buffer[i];
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
put_debug_char('#');
|
|
|
|
|
put_debug_char(hexchars[csum >> 4]);
|
|
|
|
|
put_debug_char(hexchars[csum % 16]);
|
|
|
|
|
flush_debug_buffer();
|
|
|
|
|
} while (get_debug_char() != '+');
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_command(char* buffer)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
unsigned char checksum;
|
|
|
|
|
unsigned char xmitcsum;
|
|
|
|
|
char ch;
|
|
|
|
|
unsigned int count;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
while ((ch = get_debug_char()) != '$');
|
|
|
|
|
|
|
|
|
|
checksum = 0;
|
|
|
|
|
xmitcsum = 0;
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
ch = get_debug_char();
|
|
|
|
|
if (ch == '#') break;
|
|
|
|
|
checksum = checksum + ch;
|
|
|
|
|
buffer[count] = ch;
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
buffer[count] = 0;
|
|
|
|
|
|
|
|
|
|
if (ch == '#')
|
|
|
|
|
{
|
|
|
|
|
xmitcsum = hex(get_debug_char()) << 4;
|
|
|
|
|
xmitcsum += hex(get_debug_char());
|
|
|
|
|
if (checksum != xmitcsum)
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("Bad checksum"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checksum != xmitcsum)
|
|
|
|
|
{
|
|
|
|
|
put_debug_char('-');
|
|
|
|
|
flush_debug_buffer();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
put_debug_char('+');
|
|
|
|
|
if (buffer[2] == ':')
|
|
|
|
|
{
|
|
|
|
|
put_debug_char(buffer[0]);
|
|
|
|
|
put_debug_char(buffer[1]);
|
|
|
|
|
count = strlen(buffer);
|
|
|
|
|
for (i = 3; i <= count; i++)
|
|
|
|
|
{
|
|
|
|
|
buffer[i - 3] = buffer[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
flush_debug_buffer();
|
|
|
|
|
}
|
|
|
|
|
} while (checksum != xmitcsum);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void hex2mem(char* buf, unsigned char* mem, int count)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
2008-08-16 16:29:30 +04:00
|
|
|
|
for (int i = 0; i<count; i++)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
{
|
|
|
|
|
ch = hex(*buf++) << 4;
|
|
|
|
|
ch = ch + hex(*buf++);
|
2008-08-16 16:29:30 +04:00
|
|
|
|
*mem++ = ch;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2009-05-09 11:38:12 +04:00
|
|
|
|
char* mem2hex(const Bit8u* mem, char* buf, int count)
|
2002-10-03 09:29:15 +04:00
|
|
|
|
{
|
2008-08-16 16:29:30 +04:00
|
|
|
|
for (int i = 0; i<count; i++)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
{
|
2009-07-11 10:05:17 +04:00
|
|
|
|
Bit8u ch = *mem++;
|
2008-08-16 16:29:30 +04:00
|
|
|
|
*buf++ = hexchars[ch >> 4];
|
|
|
|
|
*buf++ = hexchars[ch % 16];
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
*buf = 0;
|
|
|
|
|
return(buf);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-16 21:58:48 +03:00
|
|
|
|
int hexdigit(char c)
|
|
|
|
|
{
|
|
|
|
|
if (isdigit(c))
|
|
|
|
|
return c - '0';
|
|
|
|
|
else if (isupper(c))
|
|
|
|
|
return c - 'A' + 10;
|
|
|
|
|
else
|
|
|
|
|
return c - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit64u read_little_endian_hex(char *&buf)
|
|
|
|
|
{
|
|
|
|
|
int byte;
|
|
|
|
|
Bit64u ret = 0;
|
|
|
|
|
int n = 0;
|
|
|
|
|
while (isxdigit(*buf)) {
|
|
|
|
|
byte = hexdigit(*buf++);
|
|
|
|
|
if (isxdigit(*buf))
|
|
|
|
|
byte = (byte << 4) | hexdigit(*buf++);
|
2009-07-11 10:05:17 +04:00
|
|
|
|
ret |= (Bit64u)byte << (n*8);
|
2005-02-16 21:58:48 +03:00
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-03 09:29:15 +04:00
|
|
|
|
static int continue_thread = -1;
|
|
|
|
|
static int other_thread = 0;
|
|
|
|
|
|
2005-03-16 19:36:31 +03:00
|
|
|
|
#if !BX_SUPPORT_X86_64
|
2002-10-03 09:29:15 +04:00
|
|
|
|
#define NUMREGS (16)
|
|
|
|
|
#define NUMREGSBYTES (NUMREGS * 4)
|
2009-05-09 11:38:12 +04:00
|
|
|
|
static Bit32u registers[NUMREGS];
|
2005-02-16 21:58:48 +03:00
|
|
|
|
#endif
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
|
|
|
|
#define MAX_BREAKPOINTS (255)
|
2014-08-30 18:25:06 +04:00
|
|
|
|
static Bit64u breakpoints[MAX_BREAKPOINTS] = {0,};
|
2009-07-11 10:05:17 +04:00
|
|
|
|
static unsigned nr_breakpoints = 0;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
|
|
|
|
static int stub_trace_flag = 0;
|
|
|
|
|
static int instr_count = 0;
|
|
|
|
|
static int saved_eip = 0;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
static int bx_enter_gdbstub = 0;
|
|
|
|
|
|
|
|
|
|
void bx_gdbstub_break(void)
|
|
|
|
|
{
|
|
|
|
|
bx_enter_gdbstub = 1;
|
|
|
|
|
}
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
|
|
|
|
int bx_gdbstub_check(unsigned int eip)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
unsigned int i;
|
|
|
|
|
unsigned char ch;
|
|
|
|
|
int r;
|
2012-03-11 22:12:50 +04:00
|
|
|
|
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
fd_set fds;
|
|
|
|
|
struct timeval tv = {0, 0};
|
2014-08-30 18:25:06 +04:00
|
|
|
|
#else
|
|
|
|
|
long arg;
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#endif
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (bx_enter_gdbstub)
|
|
|
|
|
{
|
|
|
|
|
bx_enter_gdbstub = 0;
|
|
|
|
|
last_stop_reason = GDBSTUB_EXECUTION_BREAKPOINT;
|
|
|
|
|
return GDBSTUB_EXECUTION_BREAKPOINT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instr_count++;
|
|
|
|
|
|
|
|
|
|
if ((instr_count % 500) == 0)
|
|
|
|
|
{
|
2014-08-30 18:25:06 +04:00
|
|
|
|
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
FD_ZERO(&fds);
|
|
|
|
|
FD_SET(socket_fd, &fds);
|
|
|
|
|
r = select(socket_fd + 1, &fds, NULL, NULL, &tv);
|
|
|
|
|
if (r == 1)
|
|
|
|
|
{
|
|
|
|
|
r = recv(socket_fd, (char *)&ch, 1, 0);
|
|
|
|
|
}
|
2014-08-30 18:25:06 +04:00
|
|
|
|
#else
|
|
|
|
|
arg = fcntl(socket_fd, F_GETFL);
|
|
|
|
|
fcntl(socket_fd, F_SETFL, arg | O_NONBLOCK);
|
|
|
|
|
r = recv(socket_fd, &ch, 1, 0);
|
|
|
|
|
fcntl(socket_fd, F_SETFL, arg);
|
2008-02-06 01:57:43 +03:00
|
|
|
|
#endif
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (r == 1)
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("Got byte %x", (unsigned int)ch));
|
|
|
|
|
last_stop_reason = GDBSTUB_USER_BREAK;
|
|
|
|
|
return GDBSTUB_USER_BREAK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nr_breakpoints; i++)
|
|
|
|
|
{
|
|
|
|
|
if (eip == breakpoints[i])
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("found breakpoint at %x", eip));
|
|
|
|
|
last_stop_reason = GDBSTUB_EXECUTION_BREAKPOINT;
|
|
|
|
|
return GDBSTUB_EXECUTION_BREAKPOINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stub_trace_flag == 1)
|
|
|
|
|
{
|
|
|
|
|
last_stop_reason = GDBSTUB_TRACE;
|
|
|
|
|
return GDBSTUB_TRACE;
|
|
|
|
|
}
|
|
|
|
|
last_stop_reason = GDBSTUB_STOP_NO_REASON;
|
|
|
|
|
return GDBSTUB_STOP_NO_REASON;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-30 18:25:06 +04:00
|
|
|
|
static int remove_breakpoint(Bit64u addr, int len)
|
2002-10-03 09:29:15 +04:00
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (len != 1)
|
|
|
|
|
{
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-11 10:05:17 +04:00
|
|
|
|
for (unsigned i = 0; i < MAX_BREAKPOINTS; i++)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
{
|
|
|
|
|
if (breakpoints[i] == addr)
|
|
|
|
|
{
|
2014-12-18 20:52:40 +03:00
|
|
|
|
BX_INFO(("Removing breakpoint at " FMT_ADDRX64, addr));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
breakpoints[i] = 0;
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return(0);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-30 18:25:06 +04:00
|
|
|
|
static void insert_breakpoint(Bit64u addr)
|
2002-10-03 09:29:15 +04:00
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
unsigned int i;
|
|
|
|
|
|
2014-12-18 20:52:40 +03:00
|
|
|
|
BX_INFO(("Setting breakpoint at " FMT_ADDRX64, addr));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < (unsigned)MAX_BREAKPOINTS; i++)
|
|
|
|
|
{
|
|
|
|
|
if (breakpoints[i] == 0)
|
|
|
|
|
{
|
|
|
|
|
breakpoints[i] = addr;
|
|
|
|
|
if (i >= nr_breakpoints)
|
|
|
|
|
{
|
|
|
|
|
nr_breakpoints = i + 1;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BX_INFO(("No slot for breakpoint"));
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-11 10:05:17 +04:00
|
|
|
|
static void do_pc_breakpoint(int insert, Bit64u addr, int len)
|
2005-02-16 21:58:48 +03:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < len; ++i)
|
|
|
|
|
if (insert)
|
2005-02-24 22:50:36 +03:00
|
|
|
|
insert_breakpoint(addr+i);
|
2005-02-16 21:58:48 +03:00
|
|
|
|
else
|
2005-02-24 22:50:36 +03:00
|
|
|
|
remove_breakpoint(addr+i, 1);
|
2005-02-16 21:58:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_breakpoint(int insert, char* buffer)
|
|
|
|
|
{
|
|
|
|
|
char* ebuf;
|
2005-02-24 22:50:36 +03:00
|
|
|
|
unsigned long type = strtoul(buffer, &ebuf, 16);
|
2009-07-11 10:05:17 +04:00
|
|
|
|
Bit64u addr = strtoull(ebuf+1, &ebuf, 16);
|
2005-02-16 21:58:48 +03:00
|
|
|
|
unsigned long len = strtoul(ebuf+1, &ebuf, 16);
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
do_pc_breakpoint(insert, addr, len);
|
|
|
|
|
put_reply("OK");
|
2005-02-24 22:50:36 +03:00
|
|
|
|
break;
|
2005-02-16 21:58:48 +03:00
|
|
|
|
default:
|
|
|
|
|
put_reply("");
|
2005-02-24 22:50:36 +03:00
|
|
|
|
break;
|
2005-02-16 21:58:48 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-03 09:29:15 +04:00
|
|
|
|
static void write_signal(char* buf, int signal)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
buf[0] = hexchars[signal >> 4];
|
|
|
|
|
buf[1] = hexchars[signal % 16];
|
|
|
|
|
buf[2] = 0;
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-16 21:58:48 +03:00
|
|
|
|
static int access_linear(Bit64u laddress,
|
2002-10-03 09:29:15 +04:00
|
|
|
|
unsigned len,
|
|
|
|
|
unsigned int rw,
|
|
|
|
|
Bit8u* data)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
bx_phy_address phys;
|
|
|
|
|
bx_bool valid;
|
|
|
|
|
|
|
|
|
|
if (((laddress & 0xfff) + len) > 4096)
|
|
|
|
|
{
|
|
|
|
|
valid = access_linear(laddress,
|
|
|
|
|
4096 - (laddress & 0xfff),
|
|
|
|
|
rw,
|
|
|
|
|
data);
|
|
|
|
|
if (!valid) return(0);
|
|
|
|
|
|
|
|
|
|
valid = access_linear(laddress,
|
|
|
|
|
len + (laddress & 0xfff) - 4096,
|
|
|
|
|
rw,
|
2009-10-15 20:14:30 +04:00
|
|
|
|
(Bit8u *)(data + (4096 - (laddress & 0xfff))));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
return(valid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
valid = BX_CPU(0)->dbg_xlate_linear2phy(laddress, (bx_phy_address*)&phys);
|
|
|
|
|
if (!valid) return(0);
|
|
|
|
|
|
2008-12-06 01:34:42 +03:00
|
|
|
|
if (rw & 1) {
|
2020-12-08 22:52:39 +03:00
|
|
|
|
valid = BX_MEM(0)->dbg_set_mem(BX_CPU(0), phys, len, data);
|
2008-12-06 01:34:42 +03:00
|
|
|
|
} else {
|
|
|
|
|
valid = BX_MEM(0)->dbg_fetch_mem(BX_CPU(0), phys, len, data);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(valid);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void debug_loop(void)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
char buffer[255];
|
2009-05-09 11:38:12 +04:00
|
|
|
|
char obuf[1024];
|
2008-08-16 16:29:30 +04:00
|
|
|
|
int ne = 0;
|
2009-05-09 11:38:12 +04:00
|
|
|
|
Bit8u mem[255];
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
while (ne == 0)
|
|
|
|
|
{
|
2011-11-20 20:21:53 +04:00
|
|
|
|
SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set(0);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
get_command(buffer);
|
2008-08-16 16:29:30 +04:00
|
|
|
|
BX_DEBUG(("get_buffer '%s'", buffer));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// At a minimum, a stub is required to support the <20>g<EFBFBD> and <20>G<EFBFBD> commands for register access,
|
|
|
|
|
// and the <20>m<EFBFBD> and <20>M<EFBFBD> commands for memory access. Stubs that only control single-threaded
|
|
|
|
|
// targets can implement run control with the <20>c<EFBFBD> (continue), and <20>s<EFBFBD> (step) commands. Stubs
|
|
|
|
|
// that support multi-threading targets should support the <20>vCont<6E> command. All other commands
|
|
|
|
|
// are optional.
|
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
switch (buffer[0])
|
|
|
|
|
{
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// 'c [addr]' Continue. addr is address to resume.
|
|
|
|
|
// If addr is omitted, resume at current address.
|
|
|
|
|
// This packet is deprecated for multi-threading support. See [vCont packet]
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'c':
|
|
|
|
|
{
|
|
|
|
|
char buf[255];
|
2008-02-15 22:03:54 +03:00
|
|
|
|
Bit32u new_eip;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
if (buffer[1] != 0)
|
|
|
|
|
{
|
2008-02-15 22:03:54 +03:00
|
|
|
|
new_eip = (Bit32u) atoi(buffer + 1);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
BX_INFO(("continuing at %x", new_eip));
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<BX_SMP_PROCESSORS; i++) {
|
|
|
|
|
BX_CPU(i)->invalidate_prefetch_q();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saved_eip = EIP;
|
2008-02-15 22:03:54 +03:00
|
|
|
|
BX_CPU_THIS_PTR gen_reg[BX_32BIT_REG_EIP].dword.erx = new_eip;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stub_trace_flag = 0;
|
2011-11-20 20:21:53 +04:00
|
|
|
|
bx_cpu.cpu_loop();
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
2012-10-28 12:23:39 +04:00
|
|
|
|
SIM->refresh_vga();
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
if (buffer[1] != 0)
|
|
|
|
|
{
|
|
|
|
|
bx_cpu.invalidate_prefetch_q();
|
2008-02-15 22:03:54 +03:00
|
|
|
|
BX_CPU_THIS_PTR gen_reg[BX_32BIT_REG_EIP].dword.erx = saved_eip;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
2008-02-06 01:57:43 +03:00
|
|
|
|
BX_INFO(("stopped with %x", last_stop_reason));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
buf[0] = 'S';
|
|
|
|
|
if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT ||
|
|
|
|
|
last_stop_reason == GDBSTUB_TRACE)
|
|
|
|
|
{
|
|
|
|
|
write_signal(&buf[1], SIGTRAP);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
write_signal(&buf[1], 0);
|
|
|
|
|
}
|
|
|
|
|
put_reply(buf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// 's [addr]' Single step. addr is the address at which to resume.
|
|
|
|
|
// If addr is omitted, resume at same address.
|
|
|
|
|
// This packet is deprecated for multi-threading support. See [vCont packet]
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 's':
|
|
|
|
|
{
|
|
|
|
|
char buf[255];
|
|
|
|
|
|
|
|
|
|
BX_INFO(("stepping"));
|
|
|
|
|
stub_trace_flag = 1;
|
2011-11-20 20:21:53 +04:00
|
|
|
|
bx_cpu.cpu_loop();
|
2012-10-28 12:23:39 +04:00
|
|
|
|
SIM->refresh_vga();
|
2006-10-29 11:48:30 +03:00
|
|
|
|
stub_trace_flag = 0;
|
|
|
|
|
BX_INFO(("stopped with %x", last_stop_reason));
|
|
|
|
|
buf[0] = 'S';
|
|
|
|
|
if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT ||
|
|
|
|
|
last_stop_reason == GDBSTUB_TRACE)
|
|
|
|
|
{
|
|
|
|
|
write_signal(&buf[1], SIGTRAP);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
write_signal(&buf[1], SIGTRAP);
|
|
|
|
|
}
|
|
|
|
|
put_reply(buf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>M addr,length:XX...<2E>
|
|
|
|
|
// Write length bytes of memory starting at address addr. XX... is the data;
|
|
|
|
|
// each byte is transmitted as a two-digit hexadecimal number.
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'M':
|
|
|
|
|
{
|
|
|
|
|
unsigned char mem[255];
|
|
|
|
|
char* ebuf;
|
|
|
|
|
|
2009-07-11 10:05:17 +04:00
|
|
|
|
Bit64u addr = strtoull(&buffer[1], &ebuf, 16);
|
|
|
|
|
int len = strtoul(ebuf + 1, &ebuf, 16);
|
2008-02-06 01:57:43 +03:00
|
|
|
|
hex2mem(ebuf + 1, mem, len);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
if (len == 1 && mem[0] == 0xcc)
|
|
|
|
|
{
|
|
|
|
|
insert_breakpoint(addr);
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
}
|
|
|
|
|
else if (remove_breakpoint(addr, len))
|
|
|
|
|
{
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (access_linear(addr, len, BX_WRITE, mem))
|
|
|
|
|
{
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-02-07 20:53:06 +03:00
|
|
|
|
put_reply("Eff");
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2008-02-06 01:57:43 +03:00
|
|
|
|
break;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>m addr,length<74>
|
|
|
|
|
// Read length bytes of memory starting at address addr. Note that addr may
|
|
|
|
|
// not be aligned to any particular boundary.
|
|
|
|
|
|
|
|
|
|
// The stub need not use any particular size or alignment when gathering data
|
|
|
|
|
// from memory for the response; even if addr is word-aligned and length is a
|
|
|
|
|
// multiple of the word size, the stub is free to use byte accesses, or not. For
|
|
|
|
|
// this reason, this packet may not be suitable for accessing memory-mapped I/O
|
|
|
|
|
// devices.
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'm':
|
|
|
|
|
{
|
|
|
|
|
Bit64u addr;
|
|
|
|
|
int len;
|
|
|
|
|
char* ebuf;
|
|
|
|
|
|
|
|
|
|
addr = strtoull(&buffer[1], &ebuf, 16);
|
|
|
|
|
len = strtoul(ebuf + 1, NULL, 16);
|
2014-12-18 20:52:40 +03:00
|
|
|
|
BX_INFO(("addr " FMT_ADDRX64 " len %x", addr, len));
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
access_linear(addr, len, BX_READ, mem);
|
2009-05-09 11:38:12 +04:00
|
|
|
|
mem2hex(mem, obuf, len);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
put_reply(obuf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>P n...=r...<2E>
|
|
|
|
|
// Write register n... with value r... The register number n is in hexadecimal,
|
|
|
|
|
// and r... contains two hex digits for each byte in the register (target byte order).
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'P':
|
|
|
|
|
{
|
|
|
|
|
int reg;
|
2009-07-11 10:05:17 +04:00
|
|
|
|
Bit64u value;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
char* ebuf;
|
|
|
|
|
|
|
|
|
|
reg = strtoul(&buffer[1], &ebuf, 16);
|
2009-05-09 11:38:12 +04:00
|
|
|
|
++ebuf;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
value = read_little_endian_hex(ebuf);
|
|
|
|
|
|
2014-12-18 20:52:40 +03:00
|
|
|
|
BX_INFO(("reg %d set to " FMT_ADDRX64, reg, value));
|
2008-11-10 01:56:54 +03:00
|
|
|
|
#if BX_SUPPORT_X86_64 == 0
|
2006-10-29 11:48:30 +03:00
|
|
|
|
switch (reg)
|
|
|
|
|
{
|
2008-11-10 01:56:54 +03:00
|
|
|
|
case 0:
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
case 4:
|
|
|
|
|
case 5:
|
|
|
|
|
case 6:
|
|
|
|
|
case 7:
|
2011-09-22 22:53:20 +04:00
|
|
|
|
BX_CPU_THIS_PTR set_reg32(reg, value);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
|
EIP = value;
|
|
|
|
|
BX_CPU_THIS_PTR invalidate_prefetch_q();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-02-16 21:58:48 +03:00
|
|
|
|
#else
|
2006-10-29 11:48:30 +03:00
|
|
|
|
switch (reg)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
case 4:
|
|
|
|
|
case 5:
|
|
|
|
|
case 6:
|
|
|
|
|
case 7:
|
|
|
|
|
case 8:
|
|
|
|
|
case 9:
|
|
|
|
|
case 10:
|
|
|
|
|
case 11:
|
|
|
|
|
case 12:
|
|
|
|
|
case 13:
|
|
|
|
|
case 14:
|
|
|
|
|
case 15:
|
2011-09-22 22:53:20 +04:00
|
|
|
|
BX_CPU_THIS_PTR set_reg64(reg, value);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
|
RIP = value;
|
|
|
|
|
BX_CPU_THIS_PTR invalidate_prefetch_q();
|
|
|
|
|
break;
|
|
|
|
|
|
2002-10-03 09:29:15 +04:00
|
|
|
|
default:
|
|
|
|
|
break;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>g<EFBFBD> Read general registers.
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'g':
|
2010-02-14 18:17:14 +03:00
|
|
|
|
{
|
2008-11-10 01:56:54 +03:00
|
|
|
|
#if BX_SUPPORT_X86_64 == 0
|
2009-05-09 11:38:12 +04:00
|
|
|
|
WriteHostDWordToLittleEndian(registers + 0, EAX);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 1, ECX);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 2, EDX);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 3, EBX);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 4, ESP);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 5, EBP);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 6, ESI);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 7, EDI);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT)
|
|
|
|
|
{
|
2009-05-09 11:38:12 +04:00
|
|
|
|
WriteHostDWordToLittleEndian(registers + 8, EIP + 1);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-05-09 11:38:12 +04:00
|
|
|
|
WriteHostDWordToLittleEndian(registers + 8, EIP);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
2009-05-09 11:38:12 +04:00
|
|
|
|
WriteHostDWordToLittleEndian(registers + 9,
|
|
|
|
|
BX_CPU_THIS_PTR read_eflags());
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 10,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 11,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 12,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 13,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 14,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
|
|
|
|
WriteHostDWordToLittleEndian(registers + 15,
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
2009-07-11 10:05:17 +04:00
|
|
|
|
mem2hex((const Bit8u*) registers, obuf, NUMREGSBYTES);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
#else
|
|
|
|
|
#define PUTREG(buf, val, len) do { \
|
|
|
|
|
Bit64u u = (val); \
|
2009-07-11 10:05:17 +04:00
|
|
|
|
(buf) = mem2hex((const Bit8u*)&u, (buf), (len)); \
|
2006-10-29 11:48:30 +03:00
|
|
|
|
} while (0)
|
2009-07-11 10:05:17 +04:00
|
|
|
|
char* buf = obuf;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
PUTREG(buf, RAX, 8);
|
|
|
|
|
PUTREG(buf, RBX, 8);
|
|
|
|
|
PUTREG(buf, RCX, 8);
|
|
|
|
|
PUTREG(buf, RDX, 8);
|
|
|
|
|
PUTREG(buf, RSI, 8);
|
|
|
|
|
PUTREG(buf, RDI, 8);
|
|
|
|
|
PUTREG(buf, RBP, 8);
|
|
|
|
|
PUTREG(buf, RSP, 8);
|
|
|
|
|
PUTREG(buf, R8, 8);
|
|
|
|
|
PUTREG(buf, R9, 8);
|
|
|
|
|
PUTREG(buf, R10, 8);
|
|
|
|
|
PUTREG(buf, R11, 8);
|
|
|
|
|
PUTREG(buf, R12, 8);
|
|
|
|
|
PUTREG(buf, R13, 8);
|
|
|
|
|
PUTREG(buf, R14, 8);
|
|
|
|
|
PUTREG(buf, R15, 8);
|
|
|
|
|
Bit64u rip;
|
|
|
|
|
rip = RIP;
|
|
|
|
|
if (last_stop_reason == GDBSTUB_EXECUTION_BREAKPOINT)
|
|
|
|
|
{
|
|
|
|
|
++rip;
|
|
|
|
|
}
|
|
|
|
|
PUTREG(buf, rip, 8);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR read_eflags(), 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value, 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value, 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value, 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value, 4);
|
|
|
|
|
PUTREG(buf, BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value, 4);
|
|
|
|
|
#endif
|
|
|
|
|
put_reply(obuf);
|
|
|
|
|
break;
|
2010-02-14 18:17:14 +03:00
|
|
|
|
}
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
case '?':
|
|
|
|
|
sprintf(obuf, "S%02x", SIGTRAP);
|
|
|
|
|
put_reply(obuf);
|
|
|
|
|
break;
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>H op thread-id<69>
|
|
|
|
|
// Set thread for subsequent operations (<28>m<EFBFBD>, <20>M<EFBFBD>, <20>g<EFBFBD>, <20>G<EFBFBD>, et.al.). op depends on the
|
|
|
|
|
// operation to be performed: it should be <20>c<EFBFBD> for step and continue operations
|
|
|
|
|
// (note that this is deprecated, supporting the <20>vCont<6E> command is a better option),
|
|
|
|
|
// <20>g<EFBFBD> for other operations. The thread designator thread-id has the format
|
|
|
|
|
// and interpretation described in [thread-id syntax]
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'H':
|
|
|
|
|
if (buffer[1] == 'c')
|
|
|
|
|
{
|
|
|
|
|
continue_thread = strtol(&buffer[2], NULL, 16);
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
}
|
|
|
|
|
else if (buffer[1] == 'g')
|
|
|
|
|
{
|
|
|
|
|
other_thread = strtol(&buffer[2], NULL, 16);
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-02-07 20:53:06 +03:00
|
|
|
|
put_reply("Eff");
|
2006-10-29 11:48:30 +03:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>q name params...<2E>
|
|
|
|
|
// <20>Q name params...<2E>
|
|
|
|
|
// General query (<28>q<EFBFBD>) and set (<28>Q<EFBFBD>). These packets are described fully in
|
|
|
|
|
// Section E.4 [General Query Packets]
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'q':
|
|
|
|
|
if (buffer[1] == 'C')
|
|
|
|
|
{
|
2011-11-20 20:21:53 +04:00
|
|
|
|
sprintf(obuf, FMT_ADDRX64, (Bit64u)1);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
put_reply(obuf);
|
|
|
|
|
}
|
|
|
|
|
else if (strncmp(&buffer[1], "Offsets", strlen("Offsets")) == 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf(obuf, "Text=%x;Data=%x;Bss=%x",
|
|
|
|
|
SIM->get_param_num("text_base", gdbstub_list)->get(),
|
|
|
|
|
SIM->get_param_num("data_base", gdbstub_list)->get(),
|
|
|
|
|
SIM->get_param_num("bss_base", gdbstub_list)->get());
|
|
|
|
|
put_reply(obuf);
|
|
|
|
|
}
|
2008-08-16 16:29:30 +04:00
|
|
|
|
else if (strncmp(&buffer[1], "Supported", strlen("Supported")) == 0)
|
|
|
|
|
{
|
|
|
|
|
put_reply("");
|
|
|
|
|
}
|
2006-10-29 11:48:30 +03:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-01-03 01:36:20 +03:00
|
|
|
|
put_reply(""); /* not supported */
|
2008-02-06 01:57:43 +03:00
|
|
|
|
}
|
2006-10-29 11:48:30 +03:00
|
|
|
|
break;
|
|
|
|
|
|
2011-09-22 22:53:20 +04:00
|
|
|
|
// <20>z type,addr,kind<6E>
|
|
|
|
|
// <20>Z type,addr,kind<6E>
|
|
|
|
|
// Insert (<28>Z<EFBFBD>) or remove (<28>z<EFBFBD>) a type breakpoint or watchpoint starting at address
|
|
|
|
|
// address of kind kind.
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'Z':
|
|
|
|
|
do_breakpoint(1, buffer+1);
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
do_breakpoint(0, buffer+1);
|
|
|
|
|
break;
|
2011-09-22 22:53:20 +04:00
|
|
|
|
|
|
|
|
|
// <20>k<EFBFBD> Kill request.
|
2006-10-29 11:48:30 +03:00
|
|
|
|
case 'k':
|
|
|
|
|
BX_PANIC(("Debugger asked us to quit"));
|
|
|
|
|
break;
|
2011-09-22 22:53:20 +04:00
|
|
|
|
|
2009-12-28 23:07:41 +03:00
|
|
|
|
case 'D':
|
|
|
|
|
BX_INFO(("Debugger detached"));
|
|
|
|
|
put_reply("OK");
|
|
|
|
|
return;
|
|
|
|
|
break;
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
put_reply("");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wait_for_connect(int portn)
|
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
struct sockaddr_in sockaddr;
|
|
|
|
|
socklen_t sockaddr_len;
|
|
|
|
|
struct protoent *protoent;
|
|
|
|
|
int r;
|
|
|
|
|
int opt;
|
|
|
|
|
|
|
|
|
|
listen_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
|
|
|
if (listen_socket_fd == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_PANIC(("Failed to create socket"));
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2008-02-06 01:57:43 +03:00
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
/* Allow rapid reuse of this port */
|
|
|
|
|
opt = 1;
|
2012-03-11 22:12:50 +04:00
|
|
|
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
r = setsockopt(listen_socket_fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#else
|
2006-10-29 11:48:30 +03:00
|
|
|
|
r = setsockopt(listen_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#endif
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (r == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("setsockopt(SO_REUSEADDR) failed"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset (&sockaddr, '\000', sizeof sockaddr);
|
2002-11-09 00:29:16 +03:00
|
|
|
|
#if BX_HAVE_SOCKADDR_IN_SIN_LEN
|
2006-10-29 11:48:30 +03:00
|
|
|
|
// if you don't have sin_len change that to #if 0. This is the subject of
|
|
|
|
|
// bug [ 626840 ] no 'sin_len' in 'struct sockaddr_in'.
|
|
|
|
|
sockaddr.sin_len = sizeof sockaddr;
|
2002-10-22 16:50:56 +04:00
|
|
|
|
#endif
|
2006-10-29 11:48:30 +03:00
|
|
|
|
sockaddr.sin_family = AF_INET;
|
|
|
|
|
sockaddr.sin_port = htons(portn);
|
2006-10-29 21:44:49 +03:00
|
|
|
|
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
r = bind(listen_socket_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
|
|
|
|
if (r == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_PANIC(("Failed to bind socket"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = listen(listen_socket_fd, 0);
|
|
|
|
|
if (r == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_PANIC(("Failed to listen on socket"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sockaddr_len = sizeof sockaddr;
|
|
|
|
|
socket_fd = accept(listen_socket_fd, (struct sockaddr *)&sockaddr, &sockaddr_len);
|
|
|
|
|
if (socket_fd == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_PANIC(("Failed to accept on socket"));
|
|
|
|
|
}
|
2015-05-25 15:33:39 +03:00
|
|
|
|
closesocket(listen_socket_fd);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
|
|
|
|
|
protoent = getprotobyname ("tcp");
|
|
|
|
|
if (!protoent)
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("getprotobyname (\"tcp\") failed"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable Nagle - allow small packets to be sent without delay. */
|
|
|
|
|
opt = 1;
|
2012-03-11 22:12:50 +04:00
|
|
|
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
r = setsockopt (socket_fd, protoent->p_proto, TCP_NODELAY, (const char *)&opt, sizeof(opt));
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#else
|
2006-10-29 11:48:30 +03:00
|
|
|
|
r = setsockopt (socket_fd, protoent->p_proto, TCP_NODELAY, &opt, sizeof(opt));
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#endif
|
2006-10-29 11:48:30 +03:00
|
|
|
|
if (r == -1)
|
|
|
|
|
{
|
|
|
|
|
BX_INFO(("setsockopt(TCP_NODELAY) failed"));
|
|
|
|
|
}
|
2006-10-29 21:44:49 +03:00
|
|
|
|
Bit32u ip = sockaddr.sin_addr.s_addr;
|
|
|
|
|
printf("Connected to %d.%d.%d.%d\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|
|
|
|
|
|
2006-10-26 21:27:04 +04:00
|
|
|
|
void bx_gdbstub_init(void)
|
2002-10-03 09:29:15 +04:00
|
|
|
|
{
|
2006-10-29 11:48:30 +03:00
|
|
|
|
gdbstublog = new logfunctions();
|
|
|
|
|
gdbstublog->put("GDBST");
|
|
|
|
|
gdbstublog->setonoff(LOGLEV_PANIC, ACT_FATAL);
|
2006-10-26 21:27:04 +04:00
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
gdbstub_list = (bx_list_c*) SIM->get_param(BXPN_GDBSTUB);
|
|
|
|
|
int portn = SIM->get_param_num("port", gdbstub_list)->get();
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
2012-03-11 22:12:50 +04:00
|
|
|
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
2006-10-29 11:48:30 +03:00
|
|
|
|
WSADATA wsaData;
|
|
|
|
|
WSAStartup(2, &wsaData);
|
2004-11-01 20:14:02 +03:00
|
|
|
|
#endif
|
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
/* Wait for connect */
|
2006-10-29 21:44:49 +03:00
|
|
|
|
printf("Waiting for gdb connection on port %d\n", portn);
|
2006-10-29 11:48:30 +03:00
|
|
|
|
wait_for_connect(portn);
|
|
|
|
|
|
|
|
|
|
/* Do debugger command loop */
|
|
|
|
|
debug_loop();
|
2002-10-03 09:29:15 +04:00
|
|
|
|
|
2006-10-29 11:48:30 +03:00
|
|
|
|
/* CPU loop */
|
2011-11-20 20:21:53 +04:00
|
|
|
|
bx_cpu.cpu_loop();
|
2017-03-07 00:30:05 +03:00
|
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
WSACleanup();
|
|
|
|
|
#endif
|
2002-10-03 09:29:15 +04:00
|
|
|
|
}
|