Line 59... |
Line 59... |
// 090304 Finished RSP server code import, added extra
|
// 090304 Finished RSP server code import, added extra
|
// functions, adding stability when debugging on
|
// functions, adding stability when debugging on
|
// a remote target. jb
|
// a remote target. jb
|
// 090505 Remove PPC polling - caused intermittent errors
|
// 090505 Remove PPC polling - caused intermittent errors
|
// in or1k jb
|
// in or1k jb
|
|
// 090828 Fixed byte/non-aligned accesses. Removed legacy
|
|
// "remote JTAG" protocol. jb
|
#ifdef CYGWIN_COMPILE
|
#ifdef CYGWIN_COMPILE
|
|
|
#else
|
#else
|
// linux includes
|
// linux includes
|
#include <time.h>
|
#include <time.h>
|
Line 213... |
Line 214... |
} stallState;
|
} stallState;
|
|
|
int npcIsCached; //!< Is the NPC cached - should be bool
|
int npcIsCached; //!< Is the NPC cached - should be bool
|
uint32_t npcCachedValue; //!< Cached value of the NPC
|
uint32_t npcCachedValue; //!< Cached value of the NPC
|
|
|
|
/* OR32 Linux kernel debugging hacks */
|
|
/* If we're operating in virtual memory space, currently the standard VM base
|
|
is 0xc0000000, since the GDB we're currently using is bare-metal we will
|
|
do a translation of these VM addresses to their physical address - although
|
|
not with any sophistication, we simply map all 0xc0000000 based addresses
|
|
to 0x0. This allows GDB to read/wite the addresses the PC and NPC point to,
|
|
access VM data areas, etc. */
|
|
/* Define OR32_KERNEL_DBUG_COMPAT=1 when compiling to enable this */
|
|
#define OR32_KERNEL_DBG_COMPAT 1
|
|
#define OR32_LINUX_VM_OFFSET 0xc0000000
|
|
#define OR32_LINUX_VM_MASK 0xf0000000
|
|
|
|
#define IS_VM_ADDR(adr) ((adr & OR32_LINUX_VM_MASK) == OR32_LINUX_VM_OFFSET)
|
|
|
|
|
|
|
|
|
/************************
|
/************************
|
JTAG Server Routines
|
JTAG Server Routines
|
Line 272... |
Line 287... |
|
|
/* Forward declarations of static functions */
|
/* Forward declarations of static functions */
|
static char *printTime(void);
|
static char *printTime(void);
|
static int gdb_read(void*, int);
|
static int gdb_read(void*, int);
|
static int gdb_write(void*, int);
|
static int gdb_write(void*, int);
|
static void ProtocolClean(int, int32_t);
|
|
static void GDBRequest(void);
|
|
static void rsp_interrupt();
|
static void rsp_interrupt();
|
static char rsp_peek();
|
static char rsp_peek();
|
static struct rsp_buf *get_packet (void);
|
static struct rsp_buf *get_packet (void);
|
static void rsp_init (void);
|
static void rsp_init (void);
|
static void set_npc (uint32_t addr);
|
static void set_npc (uint32_t addr);
|
Line 327... |
Line 340... |
static void swap_buf(char* p_buf, int len);
|
static void swap_buf(char* p_buf, int len);
|
static void set_stall_state (int state);
|
static void set_stall_state (int state);
|
static void reset_or1k (void);
|
static void reset_or1k (void);
|
static void gdb_ensure_or1k_stalled();
|
static void gdb_ensure_or1k_stalled();
|
static int gdb_set_chain(int chain);
|
static int gdb_set_chain(int chain);
|
|
static int gdb_write_byte(uint32_t adr, uint8_t data);
|
static int gdb_write_reg(uint32_t adr, uint32_t data);
|
static int gdb_write_reg(uint32_t adr, uint32_t data);
|
static int gdb_read_reg(uint32_t adr, uint32_t *data);
|
static int gdb_read_reg(uint32_t adr, uint32_t *data);
|
static int gdb_write_block(uint32_t adr, uint32_t *data, int len);
|
static int gdb_write_block(uint32_t adr, uint32_t *data, int len);
|
static int gdb_read_block(uint32_t adr, uint32_t *data, int len);
|
static int gdb_read_block(uint32_t adr, uint32_t *data, int len);
|
|
|
Line 444... |
Line 458... |
|
|
if (rsp.client_waiting)
|
if (rsp.client_waiting)
|
#ifdef CYGWIN_COMPILE
|
#ifdef CYGWIN_COMPILE
|
sleep(1);
|
sleep(1);
|
#else
|
#else
|
|
usleep(10000);
|
sched_yield();
|
sched_yield();
|
#endif
|
#endif
|
|
|
|
|
}
|
}
|
Line 473... |
Line 488... |
else
|
else
|
#ifdef CYGWIN_COMPILE
|
#ifdef CYGWIN_COMPILE
|
sleep(1);
|
sleep(1);
|
#else
|
#else
|
{
|
{
|
|
usleep(10000);
|
sched_yield();
|
sched_yield();
|
}
|
}
|
#endif
|
#endif
|
|
|
}
|
}
|
Line 2158... |
Line 2174... |
{
|
{
|
unsigned int addr; /* Where to read the memory */
|
unsigned int addr; /* Where to read the memory */
|
int len; /* Number of bytes to read */
|
int len; /* Number of bytes to read */
|
int off; /* Offset into the memory */
|
int off; /* Offset into the memory */
|
uint32_t temp_uint32 = 0;
|
uint32_t temp_uint32 = 0;
|
char *rec_buf;
|
char *rec_buf, *rec_buf_ptr;
|
|
int bytes_per_word = 4; /* Current OR implementation is 4-byte words */
|
|
int i;
|
|
int len_cpy;
|
|
/* Couple of temps we might need when doing aligning/leftover accesses */
|
|
uint32_t tmp_word;
|
|
char *tmp_word_ptr = (char*) &tmp_word;
|
|
|
|
|
|
|
if (2 != sscanf (p_buf->data, "m%x,%x:", &addr, &len))
|
if (2 != sscanf (p_buf->data, "m%x,%x:", &addr, &len))
|
{
|
{
|
fprintf (stderr, "Warning: Failed to recognize RSP read memory "
|
fprintf (stderr, "Warning: Failed to recognize RSP read memory "
|
Line 2179... |
Line 2202... |
len = (GDB_BUF_MAX - 1) / 2;
|
len = (GDB_BUF_MAX - 1) / 2;
|
}
|
}
|
|
|
if(!(rec_buf = (char*)malloc(len))) {
|
if(!(rec_buf = (char*)malloc(len))) {
|
put_str_packet ("E01");
|
put_str_packet ("E01");
|
ProtocolClean(0, JTAG_PROXY_OUT_OF_MEMORY);
|
|
return;
|
return;
|
}
|
}
|
|
|
// Make sure the processor is stalled
|
// Make sure the processor is stalled
|
gdb_ensure_or1k_stalled();
|
gdb_ensure_or1k_stalled();
|
Line 2194... |
Line 2216... |
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
|
if (DEBUG_GDB) printf("Error %d in gdb_set_chain\n", err);
|
put_str_packet ("E01");
|
put_str_packet ("E01");
|
return;
|
return;
|
}
|
}
|
|
|
// Read the data from Wishbone Memory chain
|
len_cpy = len;
|
err = gdb_read_block(addr, (uint32_t*)rec_buf, len);
|
rec_buf_ptr = rec_buf; // Need to save a copy of pointer
|
|
|
|
if (addr & 0x3) // address not aligned at the start
|
|
{
|
|
// Have to read from the word-aligned address first and fetch the bytes
|
|
// we need.
|
|
if (DEBUG_GDB)
|
|
printf("rsp_read_mem: unaligned address read - reading before bytes\n",
|
|
err);
|
|
int num_bytes_to_align = bytes_per_word - (addr & 0x3);
|
|
uint32_t aligned_addr = addr & ~0x3;
|
|
|
|
if (DEBUG_GDB)
|
|
printf("rsp_read_mem: reading first %d of %d overall, from 0x%.8x\n",
|
|
num_bytes_to_align, len_cpy, aligned_addr);
|
|
|
|
err = gdb_read_reg(aligned_addr, &tmp_word);
|
|
|
|
if (DEBUG_GDB) printf("rsp_read_mem: first word 0x%.8x\n", tmp_word);
|
|
|
if(err){
|
if(err){
|
put_str_packet ("E01");
|
put_str_packet ("E01");
|
return;
|
return;
|
}
|
}
|
|
|
/* Refill the buffer with the reply */
|
// Pack these bytes in first
|
for( off = 0 ; off < len ; off ++ ) {
|
if (num_bytes_to_align > len_cpy) num_bytes_to_align = len_cpy;
|
;
|
|
temp_uint32 = (temp_uint32 << 8) | (0x000000ff & *(rec_buf + off));
|
|
|
|
if((off %4 ) == 3){
|
// Data returns back in big endian format.
|
temp_uint32 = htonl(temp_uint32);
|
if (DEBUG_GDB_BLOCK_DATA)printf("rsp_read_mem: packing first bytes ");
|
reg2hex (temp_uint32, &(p_buf->data[off * 2 - 6]));
|
i=addr&0x3; int buf_ctr = 0;
|
|
while (buf_ctr < num_bytes_to_align)
|
|
{
|
|
rec_buf_ptr[buf_ctr] = tmp_word_ptr[i];
|
|
if (DEBUG_GDB_BLOCK_DATA)printf("i=%d=0x%x, ", i,
|
|
tmp_word_ptr[bytes_per_word-1-i]);
|
|
i++;
|
|
buf_ctr++;
|
|
}
|
|
|
|
if (DEBUG_GDB_BLOCK_DATA)printf("\n");
|
|
|
|
// Adjust our status
|
|
len_cpy -= num_bytes_to_align; addr += num_bytes_to_align;
|
|
rec_buf_ptr += num_bytes_to_align;
|
|
}
|
|
if (len_cpy/bytes_per_word) // Now perform all full word accesses
|
|
{
|
|
int words_to_read = len_cpy/bytes_per_word; // Full words to read
|
|
if (DEBUG_GDB) printf("rsp_read_mem: reading %d words from 0x%.8x\n",
|
|
words_to_read, addr);
|
|
// Read full data words from Wishbone Memory chain
|
|
err = gdb_read_block(addr, (uint32_t*)rec_buf_ptr,
|
|
words_to_read*bytes_per_word);
|
|
|
|
if(err){
|
|
put_str_packet ("E01");
|
|
return;
|
}
|
}
|
if (DEBUG_GDB_BLOCK_DATA){
|
|
switch(off % 16)
|
// Adjust our status
|
|
len_cpy -= (words_to_read*bytes_per_word);
|
|
addr += (words_to_read*bytes_per_word);
|
|
rec_buf_ptr += (words_to_read*bytes_per_word);
|
|
}
|
|
if (len_cpy) // Leftover bytes
|
{
|
{
|
case 3:
|
if (DEBUG_GDB)
|
printf("Add 0x%08x Data 0x%08x ", addr + off - 3, temp_uint32);
|
printf("rsp_read_mem: reading %d left-over bytes from 0x%.8x\n",
|
break;
|
len_cpy, addr);
|
case 7:
|
|
case 11:
|
err = gdb_read_reg(addr, &tmp_word);
|
printf("0x%08x ", temp_uint32);
|
|
break;
|
// Big endian - top byte first!
|
case 15:
|
for(i=0;i<len_cpy;i++)
|
printf("0x%08x\n", temp_uint32);
|
rec_buf_ptr[i] = tmp_word_ptr[i];
|
break;
|
|
default:
|
|
break;
|
|
}
|
}
|
if ((len - off == 1) && (off % 16) < 15) printf("\n");
|
|
|
if (DEBUG_GDB)
|
|
printf("rsp_read_mem: err: %d\n",err);
|
|
|
|
|
|
if(err){
|
|
put_str_packet ("E01");
|
|
return;
|
}
|
}
|
|
|
|
/* Refill the buffer with the reply */
|
|
for( off = 0 ; off < len ; off ++ ) {
|
|
;
|
|
p_buf->data[(2*off)] = hexchars[((rec_buf[off]&0xf0)>>4)];
|
|
p_buf->data[(2*off)+1] = hexchars[(rec_buf[off]&0x0f)];
|
}
|
}
|
|
|
if (DEBUG_GDB && (err > 0)) printf("\nError %x\n", err);fflush (stdout);
|
if (DEBUG_GDB && (err > 0)) printf("\nError %x\n", err);fflush (stdout);
|
free(rec_buf);
|
free(rec_buf);
|
p_buf->data[off * 2] = 0; /* End of string */
|
p_buf->data[off * 2] = 0; /* End of string */
|
p_buf->len = strlen (p_buf->data);
|
p_buf->len = strlen (p_buf->data);
|
|
if (DEBUG_GDB_BLOCK_DATA){
|
|
printf("rsp_read_mem: adr 0x%.8x data: ", addr);
|
|
for(i=0;i<len*2;i++)
|
|
printf("%c",p_buf->data[i]);
|
|
printf("\n");
|
|
}
|
|
|
put_packet (p_buf);
|
put_packet (p_buf);
|
|
|
} /* rsp_read_mem () */
|
} /* rsp_read_mem () */
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*!Handle a RSP write memory (symbolic) request ("M")
|
/*!Handle a RSP write memory (symbolic) request ("M")
|
Line 3036... |
Line 3126... |
static void
|
static void
|
rsp_write_mem_bin (struct rsp_buf *p_buf)
|
rsp_write_mem_bin (struct rsp_buf *p_buf)
|
{
|
{
|
unsigned int addr; /* Where to write the memory */
|
unsigned int addr; /* Where to write the memory */
|
int len; /* Number of bytes to write */
|
int len; /* Number of bytes to write */
|
char *bindat; /* Pointer to the binary data */
|
char *bindat, *bindat_ptr; /* Pointer to the binary data */
|
int off = 0; /* Offset to start of binary data */
|
int off = 0; /* Offset to start of binary data */
|
int newlen; /* Number of bytes in bin data */
|
int newlen; /* Number of bytes in bin data */
|
|
int i;
|
|
int bytes_per_word = 4; /* Current OR implementation is 4-byte words */
|
|
|
if (2 != sscanf (p_buf->data, "X%x,%x:", &addr, &len))
|
if (2 != sscanf (p_buf->data, "X%x,%x:", &addr, &len))
|
{
|
{
|
fprintf (stderr, "Warning: Failed to recognize RSP write memory "
|
fprintf (stderr, "Warning: Failed to recognize RSP write memory "
|
"command: %s\n", p_buf->data);
|
"command: %s\n", p_buf->data);
|
Line 3088... |
Line 3180... |
}
|
}
|
|
|
/* Write the bytes to memory */
|
/* Write the bytes to memory */
|
if (len)
|
if (len)
|
{
|
{
|
swap_buf(bindat, len);
|
//swap_buf(bindat, len);
|
|
|
if (DEBUG_GDB_BLOCK_DATA){
|
if (DEBUG_GDB_BLOCK_DATA){
|
uint32_t temp_uint32;
|
uint32_t temp_uint32;
|
for (off = 0; off < len; off++){
|
for (off = 0; off < len; off++){
|
temp_uint32 = (temp_uint32 << 8) | (0x000000ff & bindat[off]);
|
temp_uint32 = (temp_uint32 << 8) | (0x000000ff & bindat[off]);
|
if((off %4 ) == 3){
|
if((off %4 ) == 3){
|
temp_uint32 = htonl(temp_uint32);
|
//temp_uint32 = htonl(temp_uint32);
|
}
|
}
|
switch(off % 16)
|
switch(off % 16)
|
{
|
{
|
case 3:
|
case 3:
|
printf("Add 0x%08x Data 0x%08x ", addr + off - 3, temp_uint32);
|
printf("Add 0x%08x Data 0x%08x ", addr + off - 3, temp_uint32);
|
Line 3116... |
Line 3207... |
}
|
}
|
if ((len - off == 1) && (off % 16) < 15) printf("\n");
|
if ((len - off == 1) && (off % 16) < 15) printf("\n");
|
}
|
}
|
}
|
}
|
|
|
err = gdb_write_block(addr, (uint32_t*)bindat, len);
|
bindat_ptr = bindat; // Copy pointer so we don't trash the original.
|
|
if (addr & 0x3) // not perfectly aligned at beginning - fix
|
|
{
|
|
if (DEBUG_GDB) {
|
|
printf("rsp_write_mem_bin: address not word aligned: 0x%.8x\n",
|
|
addr);fflush (stdout);
|
|
}
|
|
// Write enough to align us
|
|
int bytes_to_write = bytes_per_word - (addr&0x3);
|
|
if (bytes_to_write > len) bytes_to_write = len; // case of writing 1 byte to adr 0x1
|
|
if (DEBUG_GDB) {
|
|
printf("rsp_write_mem_bin: writing %d bytes of len (%d)\n",
|
|
bytes_to_write, len);fflush (stdout);
|
|
}
|
|
|
|
for (i=0;i<bytes_to_write;i++)
|
|
err = gdb_write_byte(addr+i, (uint8_t) bindat_ptr[i]);
|
|
|
|
addr += bytes_to_write; bindat_ptr += bytes_to_write;
|
|
len -= bytes_to_write;
|
|
if (DEBUG_GDB){
|
|
printf("rsp_write_mem_bin: address should now be word aligned: 0x%.8x\n", addr);
|
|
fflush (stdout);
|
|
}
|
|
}
|
|
if ((len > 3) && !err) // now write full words, if we can
|
|
{
|
|
int words_to_write = len/bytes_per_word;
|
|
if (DEBUG_GDB)
|
|
printf("rsp_write_mem_bin: writing %d words from 0x%x, len %d bytes\n",
|
|
words_to_write, addr, len);fflush (stdout);
|
|
|
|
err = gdb_write_block(addr, (uint32_t*)bindat_ptr,
|
|
(words_to_write*bytes_per_word));
|
|
|
|
addr+=(words_to_write*bytes_per_word);
|
|
bindat_ptr+=(words_to_write*bytes_per_word);
|
|
len-=(words_to_write*bytes_per_word);
|
|
}
|
|
if (len && !err) // leftover words. Write them out
|
|
{
|
|
if (DEBUG_GDB)
|
|
printf("rsp_write_mem_bin: writing remainder %d bytes to 0x%.8x\n",
|
|
len, addr);fflush (stdout);
|
|
|
|
for (i=0;i<len;i++)
|
|
err = gdb_write_byte(addr+i, (uint8_t) bindat_ptr[i]);
|
|
}
|
|
|
if(err){
|
if(err){
|
put_str_packet ("E01");
|
put_str_packet ("E01");
|
return;
|
return;
|
}
|
}
|
|
|
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
|
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
|
}
|
}
|
put_str_packet ("OK");
|
put_str_packet ("OK");
|
|
|
} /* rsp_write_mem_bin () */
|
} /* rsp_write_mem_bin () */
|
Line 3275... |
Line 3415... |
// Arc Sim Code --> mp_hash_add (type, addr, eval_direct32 (addr, 0, 0));
|
// Arc Sim Code --> mp_hash_add (type, addr, eval_direct32 (addr, 0, 0));
|
gdb_read_block(addr, &instr, 4);
|
gdb_read_block(addr, &instr, 4);
|
|
|
mp_hash_add (type, addr, instr);
|
mp_hash_add (type, addr, instr);
|
|
|
// Arc Sim Code --> set_program32 (addr, OR1K_TRAP_INSTR);
|
//instr = OR1K_TRAP_INSTR;
|
instr = OR1K_TRAP_INSTR;
|
instr = ntohl(OR1K_TRAP_INSTR);// Endianess of this needs to be swapped -jb
|
err = gdb_write_block(addr, &instr, 4);
|
err = gdb_write_block(addr, &instr, 4);
|
if(err){
|
if(err){
|
put_str_packet ("E01");
|
put_str_packet ("E01");
|
return;
|
return;
|
}
|
}
|
Line 3360... |
Line 3500... |
printf("Stalling or1k\n");
|
printf("Stalling or1k\n");
|
dbg_cpu0_write_ctrl(0, 0x01); // stall or1k
|
dbg_cpu0_write_ctrl(0, 0x01); // stall or1k
|
}
|
}
|
}
|
}
|
|
|
|
int gdb_write_byte(uint32_t adr, uint8_t data) {
|
|
|
int gdb_read_reg(uint32_t adr, uint32_t *data) {
|
#ifdef OR32_KERNEL_DBG_COMPAT
|
|
if (IS_VM_ADDR(adr))
|
|
adr = adr & ~OR32_LINUX_VM_MASK;
|
|
#endif
|
|
|
|
if (DEBUG_CMDS) printf("wbyte %d\n", gdb_chain);
|
switch (gdb_chain) {
|
switch (gdb_chain) {
|
case SC_RISC_DEBUG: return dbg_cpu0_read(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_WISHBONE: return dbg_wb_write8(adr, data) ?
|
case SC_REGISTER: return dbg_cpu0_read_ctrl(adr, (unsigned char*)data) ?
|
|
ERR_CRC : ERR_NONE;
|
ERR_CRC : ERR_NONE;
|
case SC_WISHBONE: return dbg_wb_read32(adr, data) ? ERR_CRC : ERR_NONE;
|
|
case SC_TRACE: *data = 0; return 0;
|
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
}
|
}
|
}
|
}
|
|
|
int gdb_write_reg(uint32_t adr, uint32_t data) {
|
int gdb_write_reg(uint32_t adr, uint32_t data) {
|
|
|
|
#ifdef OR32_KERNEL_DBG_COMPAT
|
|
if (IS_VM_ADDR(adr))
|
|
adr = adr & ~OR32_LINUX_VM_MASK;
|
|
#endif
|
|
|
|
|
switch (gdb_chain) { /* remap registers, to be compatible with jp1 */
|
switch (gdb_chain) { /* remap registers, to be compatible with jp1 */
|
case SC_RISC_DEBUG: if (adr == JTAG_RISCOP) adr = 0x00;
|
case SC_RISC_DEBUG: if (adr == JTAG_RISCOP) adr = 0x00;
|
return dbg_cpu0_write(adr, data) ? ERR_CRC : ERR_NONE;
|
return dbg_cpu0_write(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_REGISTER: return dbg_cpu0_write_ctrl(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_REGISTER: return dbg_cpu0_write_ctrl(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_WISHBONE: return dbg_wb_write32(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_WISHBONE: return dbg_wb_write32(adr, data) ? ERR_CRC : ERR_NONE;
|
case SC_TRACE: return 0;
|
case SC_TRACE: return 0;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
}
|
}
|
}
|
}
|
|
int gdb_read_reg(uint32_t adr, uint32_t *data) {
|
|
|
|
#ifdef OR32_KERNEL_DBG_COMPAT
|
|
if (IS_VM_ADDR(adr))
|
|
adr = adr & ~OR32_LINUX_VM_MASK;
|
|
#endif
|
|
|
|
switch (gdb_chain) {
|
|
case SC_RISC_DEBUG: return dbg_cpu0_read(adr, data) ? ERR_CRC : ERR_NONE;
|
|
case SC_REGISTER: return dbg_cpu0_read_ctrl(adr, (unsigned char*)data) ?
|
|
ERR_CRC : ERR_NONE;
|
|
case SC_WISHBONE: return dbg_wb_read32(adr, data) ? ERR_CRC : ERR_NONE;
|
|
case SC_TRACE: *data = 0; return 0;
|
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
|
}
|
|
}
|
|
|
|
|
int gdb_read_block(uint32_t adr, uint32_t *data, int len) {
|
int gdb_read_block(uint32_t adr, uint32_t *data, int len) {
|
|
|
|
#ifdef OR32_KERNEL_DBG_COMPAT
|
|
if (IS_VM_ADDR(adr))
|
|
adr = adr & ~OR32_LINUX_VM_MASK;
|
|
#endif
|
|
|
if (DEBUG_CMDS) printf("rb %d\n", gdb_chain);
|
if (DEBUG_CMDS) printf("rb %d\n", gdb_chain);
|
|
|
switch (gdb_chain) {
|
switch (gdb_chain) {
|
case SC_WISHBONE: return dbg_wb_read_block32(adr, data, len) ?
|
case SC_WISHBONE:
|
ERR_CRC : ERR_NONE;
|
{
|
|
return dbg_wb_read_block32(adr, data, len) ? ERR_CRC : ERR_NONE;
|
|
}
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
}
|
}
|
}
|
}
|
|
|
int gdb_write_block(uint32_t adr, uint32_t *data, int len) {
|
int gdb_write_block(uint32_t adr, uint32_t *data, int len) {
|
|
|
|
#ifdef OR32_KERNEL_DBG_COMPAT
|
|
if (IS_VM_ADDR(adr))
|
|
adr = adr & ~OR32_LINUX_VM_MASK;
|
|
#endif
|
|
|
if (DEBUG_CMDS) printf("wb %d\n", gdb_chain);
|
if (DEBUG_CMDS) printf("wb %d\n", gdb_chain);
|
switch (gdb_chain) {
|
switch (gdb_chain) {
|
case SC_WISHBONE: return dbg_wb_write_block32(adr, data, len) ?
|
case SC_WISHBONE: return dbg_wb_write_block32(adr, data, len) ?
|
ERR_CRC : ERR_NONE;
|
ERR_CRC : ERR_NONE;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
Line 3412... |
Line 3594... |
return ERR_NONE;
|
return ERR_NONE;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
default: return JTAG_PROXY_INVALID_CHAIN;
|
}
|
}
|
}
|
}
|
|
|
/* Added by CZ 24/05/01 */
|
|
int GetServerSocket(const char* name, const char* proto, int port) {
|
|
struct servent *service;
|
|
struct protoent *protocol;
|
|
struct sockaddr_in sa;
|
|
struct hostent *hp;
|
|
int sockfd;
|
|
char myname[256];
|
|
//int flags; --changed to socklen_t for c++?! -- Julius
|
|
socklen_t flags;
|
|
char sTemp[256];
|
|
|
|
/* First, get the protocol number of TCP */
|
|
if (!(protocol = getprotobyname(proto))) {
|
|
sprintf(sTemp, "Unable to load protocol \"%s\"", proto);
|
|
perror(sTemp);
|
|
return 0;
|
|
}
|
|
tcp_level = protocol->p_proto; /* Save for later */
|
|
|
|
/* If we weren't passed a non standard port, get the port
|
|
from the services directory. */
|
|
if (!port && (service = getservbyname(name, protocol->p_name)))
|
|
port = ntohs(service->s_port);
|
|
|
|
/* Create the socket using the TCP protocol */
|
|
if ((sockfd = socket(PF_INET, SOCK_STREAM, protocol->p_proto)) < 0) {
|
|
perror("Unable to create socket");
|
|
return 0;
|
|
}
|
|
|
|
flags = 1;
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
|
(const char*)&flags, sizeof(int)) < 0) {
|
|
sprintf(sTemp, "Can not set SO_REUSEADDR option on socket %d", sockfd);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
|
|
/* The server should also be non blocking. Get the current flags. */
|
|
if(fcntl(sockfd, F_GETFL, &flags) < 0) {
|
|
sprintf(sTemp, "Unable to get flags for socket %d", sockfd);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
|
|
/* Set the nonblocking flag */
|
|
if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
sprintf(sTemp, "Unable to set flags for socket %d to value 0x%08x",
|
|
sockfd, flags | O_NONBLOCK);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
|
|
/* Find out what our address is */
|
|
memset(&sa, 0, sizeof(struct sockaddr_in));
|
|
gethostname(myname, sizeof(myname));
|
|
if(!(hp = gethostbyname(myname))) {
|
|
perror("Unable to read hostname");
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
|
|
/* Bind our socket to the appropriate address */
|
|
sa.sin_family = hp->h_addrtype;
|
|
sa.sin_port = htons(port);
|
|
if(bind(sockfd, (struct sockaddr*)&sa, sizeof(struct sockaddr_in)) < 0) {
|
|
sprintf(sTemp, "Unable to bind socket %d to port %d", sockfd, port);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
serverIP = sa.sin_addr.s_addr;
|
|
flags = sizeof(struct sockaddr_in);
|
|
if(getsockname(sockfd, (struct sockaddr*)&sa, &flags) < 0) {
|
|
sprintf(sTemp, "Unable to get socket information for socket %d", sockfd);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
serverPort = ntohs(sa.sin_port);
|
|
|
|
/* Set the backlog to 1 connections */
|
|
if(listen(sockfd, 1) < 0) {
|
|
sprintf(sTemp, "Unable to set backlog on socket %d to %d", sockfd, 1);
|
|
perror(sTemp);
|
|
close(sockfd);
|
|
return 0;
|
|
}
|
|
|
|
return sockfd;
|
|
}
|
|
|
|
//void HandleServerSocket(Boolean block) {
|
|
void HandleServerSocket(void) {
|
|
struct pollfd fds[2];
|
|
int n;
|
|
uint32_t temp_uint32;
|
|
|
|
rebuild:
|
|
n = 0;
|
|
if(!server_fd && !gdb_fd) return;
|
|
|
|
if(server_fd) {
|
|
fds[n].fd = server_fd;
|
|
fds[n].events = POLLIN;
|
|
fds[n++].revents = 0;
|
|
}
|
|
if(gdb_fd) {
|
|
fds[n].fd = gdb_fd;
|
|
fds[n].events = POLLIN;
|
|
fds[n++].revents = 0;
|
|
}
|
|
|
|
while(1) {
|
|
switch(poll(fds, n, -1)) {
|
|
case 0:
|
|
case -1:
|
|
if(errno == EINTR) continue;
|
|
perror("poll");
|
|
server_fd = 0;
|
|
return;
|
|
default:
|
|
/* Make sure to handle the gdb port first! */
|
|
if (gdb_fd && ((fds[0].revents && !server_fd) || (fds[1].revents && server_fd)))
|
|
{
|
|
int revents = server_fd ? fds[1].revents : fds[0].revents;
|
|
if (revents & POLLIN){
|
|
/* If we have an unacknowledged exception tell the GDB client. If this
|
|
exception was a trap due to a memory breakpoint, then adjust the NPC. */
|
|
if (rsp.client_waiting)
|
|
{
|
|
err = gdb_read_reg(PPC_CPU_REG_ADD, &temp_uint32);
|
|
if(err) printf("Error read from PPC register\n");
|
|
if ((TARGET_SIGNAL_TRAP == rsp.sigval) &&
|
|
(NULL != mp_hash_lookup (BP_MEMORY, temp_uint32)))
|
|
{
|
|
set_npc (temp_uint32);
|
|
}
|
|
|
|
rsp_report_exception();
|
|
rsp.client_waiting = 0; /* No longer waiting */
|
|
}
|
|
GDBRequest();
|
|
}
|
|
else {/* Error Occurred */
|
|
printf("\n%sSocket closed.\n",printTime());
|
|
//fprintf(stderr,
|
|
//"Received flags 0x%08x on gdb socket. Shutting down.\n", revents);
|
|
close(gdb_fd);
|
|
gdb_fd = 0;
|
|
}
|
|
}
|
|
|
|
// Go to blocking accept() instead of looping around through poll(),
|
|
// takes a loot of CPU resources and it doesn't work when
|
|
// reconnecting... Jonas Rosén
|
|
if(!gdb_fd)
|
|
{
|
|
JTAGRequest();
|
|
rsp.client_waiting = 0; /* No longer waiting */
|
|
goto rebuild;
|
|
}
|
|
|
|
if(fds[0].revents && server_fd) {
|
|
if(fds[0].revents & POLLIN) {
|
|
JTAGRequest();
|
|
rsp.client_waiting = 0; /* No longer waiting */
|
|
goto rebuild;
|
|
} else { /* Error Occurred */
|
|
fprintf(stderr,
|
|
"Received flags 0x%08x on server. Shutting down.\n",
|
|
fds[0].revents);
|
|
close(server_fd);
|
|
server_fd = 0;
|
|
serverPort = 0;
|
|
serverIP = 0;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
} /* End of switch statement */
|
|
} /* End of while statement */
|
|
}
|
|
|
|
void JTAGRequest(void) {
|
|
struct sockaddr_in sa;
|
|
struct sockaddr* addr = (struct sockaddr*)&sa;
|
|
//int n = sizeof(struct sockaddr_in); --changed to socklen_t from int type
|
|
socklen_t n = sizeof(struct sockaddr_in);
|
|
int fd = accept(server_fd, addr, &n);
|
|
int on_off = 0; /* Turn off Nagel's algorithm on the socket */
|
|
int flags;
|
|
char sTemp[256];
|
|
if (DEBUG_GDB) printf("JTAGRequest\n");
|
|
|
|
if(fd < 0) {
|
|
/* This is valid, because a connection could have started,
|
|
and then terminated due to a protocol error or user
|
|
initiation before the accept could take place. */
|
|
if(errno != EWOULDBLOCK && errno != EAGAIN) {
|
|
perror("accept");
|
|
close(server_fd);
|
|
server_fd = 0;
|
|
serverPort = 0;
|
|
serverIP = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(gdb_fd) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
if(fcntl(fd, F_GETFL, &flags) < 0) {
|
|
sprintf(sTemp, "Unable to get flags for gdb socket %d", fd);
|
|
perror(sTemp);
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
/* Rene
|
|
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
sprintf(sTemp, "Unable to set flags for gdb socket %d to value 0x%08x",
|
|
fd, flags | O_NONBLOCK);
|
|
perror(sTemp);
|
|
close(fd);
|
|
return;
|
|
} Rene */
|
|
|
|
if(setsockopt(fd, tcp_level, TCP_NODELAY, &on_off, sizeof(int)) < 0) {
|
|
sprintf(sTemp, "Unable to disable Nagel's algorithm for socket %d.\nsetsockopt", fd);
|
|
perror(sTemp);
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
printf("\n%sConnection established from %s on port %d\n", printTime(),inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));
|
|
gdb_fd = fd;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Decode the GDB command.
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
static void GDBRequest(void) {
|
|
JTAGProxyWriteMessage msg_write;
|
|
JTAGProxyReadMessage msg_read;
|
|
JTAGProxyChainMessage msg_chain;
|
|
JTAGProxyWriteResponse resp_write;
|
|
JTAGProxyReadResponse resp_read;
|
|
JTAGProxyChainResponse resp_chain;
|
|
JTAGProxyBlockWriteMessage *msg_bwrite;
|
|
JTAGProxyBlockReadMessage msg_bread;
|
|
JTAGProxyBlockWriteResponse resp_bwrite;
|
|
JTAGProxyBlockReadResponse *resp_bread;
|
|
char *p_buf;
|
|
uint32_t command;
|
|
uint32_t length;
|
|
int len, i;
|
|
|
|
/* First, we must read the incomming command */
|
|
if(gdb_read(&command, sizeof(uint32_t)) < 0) {
|
|
client_close ('1');
|
|
return;
|
|
}
|
|
command = ntohl(command);
|
|
|
|
if(gdb_read(&length, sizeof(uint32_t)) < 0) {
|
|
client_close ('2');
|
|
return;
|
|
}
|
|
length = ntohl(length);
|
|
if (DEBUG_GDB) printf("\n%s-----------------------------------------------------\nCommand %d Length %d ", printTime(), command, length);
|
|
|
|
if (DEBUG_GDB){
|
|
switch(command){
|
|
case JTAG_COMMAND_READ:
|
|
printf("JTAG_COMMAND_READ \n");
|
|
break;
|
|
case JTAG_COMMAND_WRITE:
|
|
printf("JTAG_COMMAND_WRITE \n");
|
|
break;
|
|
case JTAG_COMMAND_BLOCK_READ:
|
|
printf("JTAG_COMMAND_BLOCK_READ \n");
|
|
break;
|
|
case JTAG_COMMAND_BLOCK_WRITE:
|
|
printf("JTAG_COMMAND_BLOCK_WRITE\n");
|
|
break;
|
|
case JTAG_COMMAND_CHAIN:
|
|
printf("JTAG_COMMAND_CHAIN \n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Now, verify the protocol and implement the command */
|
|
switch(command) {
|
|
case JTAG_COMMAND_WRITE:
|
|
if(length != sizeof(msg_write) - 8) {
|
|
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
|
|
return;
|
|
}
|
|
p_buf = (char*)&msg_write;
|
|
if(gdb_read(&p_buf[8], length) < 0) {
|
|
client_close ('3');
|
|
return;
|
|
}
|
|
msg_write.address = ntohl(msg_write.address);
|
|
msg_write.data_H = ntohl(msg_write.data_H);
|
|
msg_write.data_L = ntohl(msg_write.data_L);
|
|
err = gdb_write_reg(msg_write.address, msg_write.data_L);
|
|
resp_write.status = htonl(err);
|
|
if (DEBUG_GDB) printf("Write Reg to Chain %d at add 0x%08x -> H-Data 0x%08x L-Data 0x%08x Error %d",
|
|
gdb_chain, msg_write.address, msg_write.data_H, msg_write.data_L, err);fflush (stdout);
|
|
if(gdb_write(&resp_write, sizeof(resp_write)) < 0) {
|
|
client_close ('4');
|
|
return;
|
|
}
|
|
break;
|
|
case JTAG_COMMAND_READ:
|
|
if(length != sizeof(msg_read) - 8) {
|
|
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
|
|
return;
|
|
}
|
|
p_buf = (char*)&msg_read;
|
|
if(gdb_read(&p_buf[8], length) < 0) {
|
|
client_close ('5');
|
|
return;
|
|
}
|
|
msg_read.address = ntohl(msg_read.address);
|
|
err = gdb_read_reg(msg_read.address, (uint32_t *)&resp_read.data_L);
|
|
if (DEBUG_GDB) printf("Read Reg from Chain %d at add 0x%08x", gdb_chain, msg_read.address);
|
|
resp_read.status = htonl(err);
|
|
resp_read.data_H = 0;
|
|
resp_read.data_L = htonl(resp_read.data_L);
|
|
if(gdb_write(&resp_read, sizeof(resp_read)) < 0) {
|
|
client_close ('6');
|
|
return;
|
|
}
|
|
if (DEBUG_GDB) printf(" --> Data 0x%08x Error %d\n", htonl(resp_read.data_L), err);fflush (stdout);
|
|
break;
|
|
case JTAG_COMMAND_BLOCK_WRITE:
|
|
if(length < sizeof(JTAGProxyBlockWriteMessage)-8) {
|
|
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
|
|
return;
|
|
}
|
|
if(!(p_buf = (char*)malloc(8+length))) {
|
|
ProtocolClean(length, JTAG_PROXY_OUT_OF_MEMORY);
|
|
return;
|
|
}
|
|
msg_bwrite = (JTAGProxyBlockWriteMessage*)p_buf;
|
|
if(gdb_read(&p_buf[8], length) < 0) {
|
|
client_close ('5');
|
|
free(p_buf);
|
|
return;
|
|
}
|
|
msg_bwrite->address = ntohl(msg_bwrite->address);
|
|
msg_bwrite->nRegisters = ntohl(msg_bwrite->nRegisters);
|
|
if (DEBUG_GDB) printf("Block Write to Chain %d start add 0x%08x Write %d (32 bit words):\n\n", gdb_chain, msg_bwrite->address, msg_bwrite->nRegisters);
|
|
for(i=0;i<msg_bwrite->nRegisters;i++) {
|
|
msg_bwrite->data[i] = ntohl(msg_bwrite->data[i]);
|
|
if (DEBUG_GDB_BLOCK_DATA){
|
|
if ((i % 4) == 0) printf("Add 0x%08x Data 0x%08x ", msg_bwrite->address + (i * 4), msg_bwrite->data[i]);
|
|
else if ((i % 4) == 3) printf("0x%08x\n", msg_bwrite->data[i]);
|
|
else printf("0x%08x ", msg_bwrite->data[i]);
|
|
|
|
// add a new line on the last data, but not if it is the last one in the colum
|
|
if ((msg_bwrite->nRegisters - i == 1) && (i % 4) < 3) printf("\n");
|
|
}
|
|
}
|
|
err = gdb_write_block(msg_bwrite->address, (uint32_t*)msg_bwrite->data, msg_bwrite->nRegisters * 4);
|
|
if (DEBUG_GDB) printf("Error %x\n", err);fflush (stdout);
|
|
resp_bwrite.status = htonl(err);
|
|
free(p_buf);
|
|
msg_bwrite = (JTAGProxyBlockWriteMessage *)NULL;
|
|
p_buf = (char *)msg_bwrite;
|
|
if(gdb_write(&resp_bwrite, sizeof(resp_bwrite)) < 0) {
|
|
client_close ('4');
|
|
return;
|
|
}
|
|
break;
|
|
case JTAG_COMMAND_BLOCK_READ:
|
|
if(length != sizeof(msg_bread) - 8) {
|
|
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
|
|
return;
|
|
}
|
|
p_buf = (char*)&msg_bread;
|
|
if(gdb_read(&p_buf[8], length) < 0) {
|
|
client_close ('5');
|
|
return;
|
|
}
|
|
msg_bread.address = ntohl(msg_bread.address);
|
|
msg_bread.nRegisters = ntohl(msg_bread.nRegisters);
|
|
if (DEBUG_GDB) printf("Block Read from Chain %d start add 0x%08x Read %d (32 bit words):\n\n", gdb_chain, msg_bread.address, msg_bread.nRegisters);
|
|
len = sizeof(JTAGProxyBlockReadResponse) + 4*(msg_bread.nRegisters-1);
|
|
if(!(p_buf = (char*)malloc(len))) {
|
|
ProtocolClean(0, JTAG_PROXY_OUT_OF_MEMORY);
|
|
return;
|
|
}
|
|
resp_bread = (JTAGProxyBlockReadResponse*)p_buf;
|
|
err = gdb_read_block(msg_bread.address, (uint32_t*)resp_bread->data, msg_bread.nRegisters * 4);
|
|
for(i=0;i<msg_bread.nRegisters;i++) {
|
|
/* Read previous, address next one. */
|
|
resp_bread->data[i] = htonl(resp_bread->data[i]);
|
|
if (DEBUG_GDB_BLOCK_DATA){
|
|
if ((i % 4) == 0) printf("Add 0x%08x Data 0x%08x ", msg_bread.address + (i * 4), htonl(resp_bread->data[i]));
|
|
else if ((i % 4) == 3) printf("0x%08x\n", htonl(resp_bread->data[i]));
|
|
else printf("0x%08x ", htonl(resp_bread->data[i]));
|
|
}
|
|
// add a new line on the last data, but not if it is the last one in the colum
|
|
if ((msg_bread.nRegisters - i == 1) && (i % 4) < 3) printf("\n");
|
|
}
|
|
resp_bread->status = htonl(err);
|
|
resp_bread->nRegisters = htonl(msg_bread.nRegisters);
|
|
if (DEBUG_GDB) printf("\nError %x\n", err);fflush (stdout);
|
|
if(gdb_write(resp_bread, len) < 0) {
|
|
client_close ('6');
|
|
free(p_buf);
|
|
return;
|
|
}
|
|
free(p_buf);
|
|
resp_bread = (JTAGProxyBlockReadResponse *)NULL;
|
|
p_buf = (char *)resp_bread;
|
|
break;
|
|
case JTAG_COMMAND_CHAIN:
|
|
if(length != sizeof(msg_chain) - 8) {
|
|
ProtocolClean(length, JTAG_PROXY_PROTOCOL_ERROR);
|
|
return;
|
|
}
|
|
p_buf = (char*)&msg_chain;
|
|
if(gdb_read(&p_buf[8], sizeof(msg_chain)-8) < 0) {
|
|
client_close ('7');
|
|
return;
|
|
}
|
|
msg_chain.chain = htonl(msg_chain.chain);
|
|
err = gdb_set_chain(msg_chain.chain);
|
|
resp_chain.status = htonl(err);
|
|
if (DEBUG_GDB){
|
|
switch(msg_chain.chain){
|
|
case SC_GLOBAL: /* 0 Global BS Chain */
|
|
printf("Set Chain %d Global BS Chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_RISC_DEBUG: /* 1 RISC Debug Interface chain */
|
|
printf("Set Chain %d RISC Debug Interface chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_RISC_TEST: /* 2 RISC Test Chain */
|
|
printf("Set Chain %d RISC Test Chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_TRACE: /* 3 Trace Chain */
|
|
printf("Set Chain %d Trace Chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_REGISTER: /* 4 Register Chain */
|
|
printf("Set Chain %d Register Chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_WISHBONE: /* 5 Memory chain */
|
|
printf("Set Chain %d Wishbone Memory chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
case SC_BLOCK: /* 6 Block Chains */
|
|
printf("Set Chain %d Block Chains Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
default: /* Invalid chain */
|
|
printf("Set Chain %d Invalid chain Error %x\n", msg_chain.chain, err);
|
|
break;
|
|
}
|
|
fflush (stdout);
|
|
}
|
|
if(gdb_write(&resp_chain, sizeof(resp_chain)) < 0) {
|
|
client_close ('8');
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
perror("Unknown JTAG command.");fflush (stdout);
|
|
ProtocolClean(length, JTAG_PROXY_COMMAND_NOT_IMPLEMENTED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ProtocolClean(int length, int32_t err) {
|
|
char buffer[4096];
|
|
|
|
err = htonl(err);
|
|
if(((gdb_read(buffer, length) < 0) || (gdb_write(&err, sizeof(err)) < 0)) && gdb_fd) {
|
|
perror("gdb socket - 9");
|
|
close(gdb_fd);
|
|
gdb_fd = 0;
|
|
}
|
|
}
|
|
|
|
static int gdb_write(void* p_buf, int len) {
|
|
int n;
|
|
char* w_buf = (char*)p_buf;
|
|
struct pollfd block;
|
|
|
|
while(len) {
|
|
if((n = write(gdb_fd, w_buf, len)) < 0) {
|
|
switch(errno) {
|
|
case EWOULDBLOCK: /* or EAGAIN */
|
|
/* We've been called on a descriptor marked
|
|
for nonblocking I/O. We better simulate
|
|
blocking behavior. */
|
|
block.fd = gdb_fd;
|
|
block.events = POLLOUT;
|
|
block.revents = 0;
|
|
poll(&block, 1, -1);
|
|
continue;
|
|
case EINTR:
|
|
continue;
|
|
case EPIPE:
|
|
close(gdb_fd);
|
|
gdb_fd = 0;
|
|
return -1;
|
|
default:
|
|
return -1;
|
|
}
|
|
} else {
|
|
len -= n;
|
|
w_buf += n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int gdb_read(void* p_buf, int len) {
|
|
int n;
|
|
char* r_buf = (char*)p_buf;
|
|
struct pollfd block;
|
|
|
|
while(len) {
|
|
if((n = read(gdb_fd, r_buf, len)) < 0) {
|
|
switch(errno) {
|
|
case EWOULDBLOCK: /* or EAGAIN */
|
|
/* We've been called on a descriptor marked
|
|
for nonblocking I/O. We better simulate
|
|
blocking behavior. */
|
|
block.fd = gdb_fd;
|
|
block.events = POLLIN;
|
|
block.revents = 0;
|
|
poll(&block, 1, -1);
|
|
continue;
|
|
case EINTR:
|
|
continue;
|
|
default:
|
|
return -1;
|
|
}
|
|
} else if(n == 0) {
|
|
close(gdb_fd);
|
|
gdb_fd = 0;
|
|
return -1;
|
|
} else {
|
|
len -= n;
|
|
r_buf += n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
/*****************************************************************************
|
* Close the connection to the client if it is open
|
* Close the connection to the client if it is open
|
******************************************************************************/
|
******************************************************************************/
|
static void client_close (char err)
|
static void client_close (char err)
|
{
|
{
|