Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / simcore / dbgrif.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: dbgrif.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)dbgrif.c 1.15 06/03/06 SMI"
/* FIXME: Currently this debugger interface is designed solely
* for supporting GDB. I have tried to make it as general
* as possible, but no doubt interface differences will remain
* for other debuggers.
* Ultimately, this interface will split into 2. A set of
* general interaction stubs will exist, and they
* will support loadable modules which inturn can be customised
* for each available debugger required.
*/
#include <sys/types.h>
#include <sys/socket.h>
/* #include <sys/conf.h> */
#include <stropts.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h> /* for memset in FD_ZERO */
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include "basics.h"
#include "hostcpu.h"
#include "allocate.h"
#include "strutil.h"
#include "fatal.h"
#include "createthr.h"
#include "options.h"
#include "simcore.h"
#include "config.h"
#include "regmap.h"
#include "callback.h"
#define MAX_PORT_STEP 10 /* DEFAULT_PORT to DEFAULT_PORT+9 */
/* allow upto 5 pending connections will never get that many */
#define MAX_CONNECTIONS 5
int port_offset_number; /* for more than one debugger */
bool_t flag_remdeb_if = false;
typedef enum DBGRSTATE {
DS_unattached, DS_stopped, DS_running
#if 0
/*
* available for the sim to tell the debugger about a
* new symtab to load ...
* ... something else to do eventually
*/
, DS_symtab_load
#endif
} dbgr_state_t;
typedef struct DEBUGGER {
int socket;
dbgr_state_t state;
pthread_t pthread_id;
/* ID who we are attached to - if anything */
domain_t* domainp; /* so we can read memory etc. */
/* NOTE: have to go via CPU anyway if caches modeled*/
config_proc_t* config_procp; /* config proc */
void * pspecp; /* within that proc */
/* communication buffers */
uint8_t * send_buffer_p;
uint8_t * recv_buffer_p;
uint8_t * send_ptr;
uint8_t * recv_ptr;
pthread_mutex_t stop_lock;
pthread_cond_t stop_cv;
} debugger_t;
static debugger_t dbgr;
typedef enum {
Receive_error = -1,
Dbgr_Command_Str = 0,
Sim_Command_Str_OK,
Dbgr_Attach,
Sim_Attach_OK,
Sim_Attach_Failed,
Dbgr_Read_Reg,
Sim_Reg_Value_Rtnd,
Dbgr_Write_Reg,
Sim_Reg_Written,
Sim_Reg_Write_Failed,
Dbgr_Set_Breakpoint,
Sim_Breakpoint_Set,
Dbgr_Clear_Breakpoint,
Sim_Breakpoint_Cleared,
Dbgr_Run,
Sim_Executing,
Dbgr_ReqStop,
Dbgr_Wait,
Sim_Stopped,
Sim_SimTab_Load,
Dbgr_Read_Mem,
Sim_Mem_Returned,
Sim_Mem_Read_Failed_No_Mem,
Dbgr_Write_Mem,
Sim_Mem_Write_OK,
Sim_Mem_Write_Failed_No_Mem,
Dbgr_Clear_Mem,
Sim_Mem_Clear_OK,
Sim_Mem_Clear_Failed_No_Mem,
Dbgr_Protocol_Count
} protocol_t;
#ifndef NDEBUG /* { */
#define PD(s) { s, #s },
struct {
int cmd;
char * name;
} protodebug[]= {
PD(Dbgr_Command_Str)
PD(Sim_Command_Str_OK)
PD(Dbgr_Attach)
PD(Sim_Attach_OK)
PD(Sim_Attach_Failed)
PD(Dbgr_Read_Reg)
PD(Sim_Reg_Value_Rtnd)
PD(Dbgr_Write_Reg)
PD(Sim_Reg_Written)
PD(Sim_Reg_Write_Failed)
PD(Dbgr_Set_Breakpoint)
PD(Sim_Breakpoint_Set)
PD(Dbgr_Clear_Breakpoint)
PD(Sim_Breakpoint_Cleared)
PD(Dbgr_Run)
PD(Sim_Executing)
PD(Dbgr_ReqStop)
PD(Dbgr_Wait)
PD(Sim_Stopped)
PD(Sim_SimTab_Load)
PD(Dbgr_Read_Mem)
PD(Sim_Mem_Returned)
PD(Sim_Mem_Read_Failed_No_Mem)
PD(Dbgr_Write_Mem)
PD(Sim_Mem_Write_OK)
PD(Sim_Mem_Write_Failed_No_Mem)
PD(Dbgr_Clear_Mem)
PD(Sim_Mem_Clear_OK)
PD(Sim_Mem_Clear_Failed_No_Mem)
{ -1, NULL },
};
#endif /* } */
#define MAX_BUF_SIZE 8192
static int do_recv(int skt, uint8_t * ptr, int expect);
static protocol_t recv_buffer(debugger_t * dbgp, int * nrecvdp);
static int send_buffer(debugger_t * dbgrp, protocol_t cmd, int num);
static uint16_t get_uint16(uint8_t * bp);
static void put_uint16(uint8_t * bp, uint16_t val);
static uint32_t get_uint32(uint8_t * bp);
static void put_uint32(uint8_t * bp, uint32_t val);
static uint64_t get_uint64(uint8_t * bp);
static void put_uint64(uint8_t * bp, uint64_t val);
/*
*--------------------------------------------
* Register re-map name table
* Get from the GDB numbering to the simulator
* register value ...
* ... for the moment this is for SPARC only
* but will eventually fix this ...
*--------------------------------------------
*/
static char * gdb_reg_name[] = {
#define SPARC_REG_G0 0
"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", /*values 0-31*/
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
#define SPARC_REG_F0 32
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", /* 32-63 */
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
#define SPARC_REG_F32 64
"f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", /* 64-79 */
"f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
#define SPARC_REG_PC 80
"pc", /* 80 */
#define SPARC_REG_NPC 81
"npc", /* 81 */
"ccr", /* 82 */
"fsr", /* 83 */
"fprs", /* 84 */
"y", /* 85 */
"asi", /* 86 */
"ver", /* 87 */
"tick", /* 88 */
"pil", /* 89 */
"pstate", /* 90 */
"tstate", /* 91 */
"tba", /* 92 */
"tl", /* 93 */
"tt", /* 94 */
"tpc", /* 95 */
"tnpc", /* 96 */
"wstate", /* 97 */
"cwp", /* 98 */
"cansave", /* 99 */
"canrestore", /* 100 */
"cleanwin", /* 101 */
"otherwin", /* 102 */
"asr16", /* 103 */
"asr17", /* 104 */
"asr18", /* 105 */
"asr19", /* 106 */
"asr20", /* 107 */
"asr21", /* 108 */
"asr22", /* 109 */
"asr23", /* 110 */
"asr24", /* 111 */
"asr25", /* 112 */
"asr26", /* 113 */
"asr27", /* 114 */
"asr28", /* 115 */
"asr29", /* 116 */
"asr30", /* 117 */
"asr31", /* 118 */
"icc", /* 119 */
"xcc", /* 120 */
"fcc0", /* 121 */
"fcc1", /* 122 */
"fcc2", /* 123 */
"fcc3", /* 124 */
(char*)0
};
/* Mapping for the GDB register numbering to the CPU models numbering */
int * gdb_reg_map;
static void if_exec_start(debugger_t * dbgrp);
static void if_exec_wait(debugger_t * dbgrp);
static uint64_t symtab_base;
static char * symtab_fname;
static void if_write_register(debugger_t * dbgrp);
static void if_read_register(debugger_t * dbgrp);
static void if_clear_breakpoint(debugger_t * dbgrp);
static void if_set_breakpoint(debugger_t * dbgrp);
static void if_read_memory(debugger_t * dbgrp);
static void if_write_memory(debugger_t * dbgrp);
static void if_clear_memory(debugger_t * dbgrp);
#ifndef NDEBUG
#define DBGRD(s) do { s } while (0)
#else
#define DBGRD(s) do { } while (0)
#endif
/*
* Gah this builds a map from the GDB register numbers to
* those of the sparc processor being simulated ..
* .. based on the map exported for the given
* processor type. This should be done a better way,
* but this works for now : FIXME
*/
void init_gdb_reg_map(reg_map_t * reg_mapp)
{
int count, idx;
/* for each GDB name, find and map the number the
* cpu core model expects to see
*/
for (count=0; gdb_reg_name[count]!=(char*)0; count++) ;
gdb_reg_map = Xcalloc(count, int);
for (idx=0; idx<count; idx++) {
int j;
char * matchp;
matchp = gdb_reg_name[idx];
/* brute force search for name */
for (j=0; reg_mapp[j].namep != (char*)0; j++) {
if (streq(reg_mapp[j].namep, matchp)) break;
}
/* shouldnt have gdb names we dont know ! */
assert(reg_mapp[j].namep != (char*)0);
gdb_reg_map[idx] = reg_mapp[j].idx;
}
}
static void dbgrif_stop_cb(void *arg)
{
debugger_t *dbgrp = (debugger_t *)arg;
DBGRD(printf("dbgrif_stop_cb()\n"););
dbgrp->state = DS_stopped;
pthread_mutex_lock(&dbgrp->stop_lock);
pthread_cond_broadcast(&dbgrp->stop_cv);
pthread_mutex_unlock(&dbgrp->stop_lock);
}
/*
* This new thread is invoked once contact with a debugger is
* been established. This thread exits once that debugger
* connection vanishes.
*
* Any one debugger can stop the simulation, all are required
* to be active to continue simulation.
*/
void * dbgrif(void * argp)
{
debugger_t * dbgrp = (debugger_t *)argp;
int res, length;
/*
* We have a potential contact, however we must
* setup the structures used for communication
*/
dbgrp->recv_buffer_p = (uint8_t*)valloc(MAX_BUF_SIZE);
if (dbgrp->recv_buffer_p == (uint8_t*)0) fatal("allocating recv buffer");
dbgrp->send_buffer_p = (uint8_t*)valloc(MAX_BUF_SIZE);
if (dbgrp->send_buffer_p == (uint8_t*)0) fatal("allocating send buffer");
dbgrp->recv_ptr = dbgrp->recv_buffer_p + 3;
dbgrp->send_ptr = dbgrp->send_buffer_p + 3;
/*
* Veryify the protocols match ...
* .... by exchanging the max protocol value
*
* Really should use some version checksum ... FIXME
*/
res = recv_buffer( dbgrp, &length );
send_buffer( dbgrp, Dbgr_Protocol_Count, 0 ); /* send regardless - will make other side fail too */
if (res!=Dbgr_Protocol_Count || length!=0) {
printf("Connection failed : received %d %d - debugger protocols do not match\n", res, length);
goto suicide;
}
/*
* OK we've established contact with a legitimate debugger
* run the command interface until we get the
* command to termnate this session
*/
while (1) {
int recv_len;
protocol_t cmd = (protocol_t)recv_buffer(dbgrp, &recv_len);
if (cmd == Receive_error) {
perror("failed in communication");
continue;
}
DBGRD( for (res = 0; protodebug[res].cmd!=-1 && protodebug[res].cmd!=cmd; res++) ;
printf("command [%d] : %s\n",(int)cmd,
protodebug[res].cmd != -1 ? protodebug[res].name : "illegal value"); );
switch ( cmd ) {
case Dbgr_Command_Str:
dbgrp->recv_ptr[recv_len] = '\0';
DBGRD( printf("recvd: %s\n", dbgrp->recv_ptr); );
#if 0
exec_cmds ( (char*)dbgrp->recv_ptr, cmd_ptr );
#endif
send_buffer(dbgrp, Sim_Command_Str_OK, 0);
break;
case Dbgr_Attach:
/* FIXME: for now the simulator must be in virgin state */
assert( dbgrp->state == DS_unattached);
/* Make sure simulator is stopped and ready for attach */
/* FIXME: for now this is not compatible with the auto start mode */
assert( !options.flag_auto_start );
#if 0
stop_cmd((char*)0, dbgrp->cmd_ptr); /* FIXME: prob. wrong too */
wait_for_simulation_stop(dbgrp->cmd_ptr);
if (cpu[0] == (void*)0) {
printf( "Looks like you forgot to init the architecture (file blazerc) before\n"
"you did the sttach - try again\n");
send_buffer(dbgrp->socket, Sim_Attach_Failed, 0);
dbgrp->exec_state = Exec_unattached; /* sanity */
} else {
send_buffer(dbgrp->socket, Sim_Attach_OK, 0);
dbgrp->cpup = cpu[0];
dbgrp->exec_state = Exec_stopped;
}
#endif
/* Kludge an attach just to get something
* running .... FIXME
*/
{ system_t * sysp;
sysp = LIST_ENTRY( target_config.systems, 0 );
dbgrp->domainp = LIST_ENTRY(sysp->domains, 0 );
}
dbgrp->config_procp = LIST_ENTRY(dbgrp->domainp->procs, 0);
dbgrp->pspecp = dbgrp->config_procp->proc_typep->dbgr_attach(dbgrp->domainp, dbgrp->config_procp, "0:0");
ASSERT(dbgrp->config_procp->proc_typep->proc_magic == CPU_MAGIC);
init_gdb_reg_map(dbgrp->config_procp->proc_typep->reg_mapp); /* FIXME */
if (dbgrp->pspecp == NULL) {
send_buffer(dbgrp, Sim_Attach_Failed, 0);
break;
}
dbgrp->state = DS_stopped;
send_buffer(dbgrp, Sim_Attach_OK, 0);
break;
case Dbgr_Read_Reg:
if_read_register(dbgrp);
break;
case Dbgr_Write_Reg:
if_write_register(dbgrp);
break;
case Dbgr_Set_Breakpoint:
if_set_breakpoint(dbgrp);
break;
case Dbgr_Clear_Breakpoint:
if_clear_breakpoint(dbgrp);
break;
case Dbgr_Run:
if_exec_start(dbgrp);
break;
case Dbgr_ReqStop:
/* Cannot get here ... */
fatal("Dbgr_ReqStop unexpectedly received");
case Dbgr_Wait:
if_exec_wait(dbgrp);
break;
case Dbgr_Read_Mem:
if_read_memory(dbgrp);
break;
case Dbgr_Write_Mem:
if_write_memory(dbgrp);
break;
case Dbgr_Clear_Mem:
if_clear_memory(dbgrp);
break;
default:
#ifndef NDEBUG /* { */
for (res = 0; protodebug[res].cmd != -1 && protodebug[res].cmd != cmd; res++) ;
warning("unexpected command [%d] : %s\n",(int)cmd,
protodebug[res].cmd != -1 ? protodebug[res].name : "illegal value");
#else /* } { */
warning("unexpected command %d\n",(int)cmd);
#endif /* } */
goto suicide;
}
}
suicide:;
close(dbgrp->socket);
Xfree( dbgrp->recv_buffer_p );
Xfree( dbgrp->send_buffer_p );
Xfree( dbgrp );
/*
* Clean up this debuggers session ...
* ... remove any assigned breakpoints etc ...
*/
/* FIXME */
/*
* Clean up debugger session count ?
*/
pthread_exit((void*)0);
return (void*)0; /* compiler joy */
}
#if 0 /* { */
/*
* If a symtab message is pending build the response packet
* and send it back to the debugger
*
* The buffer format is quite simple:
* uint16 offset_to_filename { from buffer start }
* uint16 number_of_sections
* Then for each section:
* uint16 offset_to_section_name { from buffer start }
* uint64 section_load_vaddr
* Then the string table:
* .. until the end of the buffer.
* (each string is null terminated)
*
*/
static void if_send_symtab_info(debugger_t * dbgrp)
{
int stridx, secidx, len;
sym_file_t * sfp;
int i;
#define SEC_SIZE (2+8)
/* grab the file info */
sfp = (sym_file_t *)dbgrp->sym_filep;
/* First size the initial sections block */
secidx = 4;
stridx = secidx + SEC_SIZE*(sfp->num_pos);
/* copy in the map name */
/* and the number of sections */
put_uint16( dbgrp->send_ptr, stridx );
put_uint16( dbgrp->send_ptr+2, sfp->num_pos );
len = strlen( sfp->mapnamep );
strcpy( (char*)dbgrp->send_ptr + stridx, sfp->mapnamep );
stridx += len+1;
for (i=0; i<sfp->num_pos; i++) {
put_uint16( dbgrp->send_ptr + secidx, stridx );
put_uint64( dbgrp->send_ptr + secidx + 2, sfp->pos[i].address );
len = strlen( sfp->pos[i].namep );
strcpy( (char*)dbgrp->send_ptr + stridx, sfp->pos[i].namep );
stridx += len + 1;
secidx += SEC_SIZE;
}
DBGRD( printf("\tif_exec_wait: returning Sim_SimTab_Load (%s)...\n", sfp->mapnamep););
send_buffer(dbgrp->socket, Sim_SimTab_Load, stridx);
symfile_cleanup(&dbgrp->sym_filep);
}
#endif /* } */
/*
* Start execution again ...
* ... this is non-blocking (use if_exec_wait to wait until stopped)
*/
static void if_exec_start(debugger_t * dbgrp)
{
DBGRD( printf("run!\n"););
dbgrp->state = DS_running;
simcore_start();
send_buffer(dbgrp, Sim_Executing, 0);
}
/*
* Wait for execution to stop, and give the appropriate response
* to the debugger ...
* ... if execution stopepd to load a symbol table signal that back
* ... after which the debugger should initiate a new run request.
*/
static void if_exec_wait(debugger_t * dbgrp)
{
DBGRD( printf("wait until stopped...\n"););
pthread_mutex_lock(&dbgrp->stop_lock);
while (dbgrp->state != DS_stopped) {
pthread_cond_wait(&dbgrp->stop_cv, &dbgrp->stop_lock);
}
pthread_mutex_unlock(&dbgrp->stop_lock);
DBGRD( printf("\tif_exec_wait: returning Sim_Stopped ...\n"););
send_buffer(dbgrp, Sim_Stopped, 0);
}
static void if_read_register(debugger_t * dbgrp)
{
int regno;
uint64_t val;
regno = (dbgrp->recv_ptr[0]<<8) | dbgrp->recv_ptr[1];
if (!dbgrp->config_procp->proc_typep->regread(dbgrp->pspecp, gdb_reg_map[regno], &val)) {
warning("Register %d [%s] fetch failed", regno, gdb_reg_name[regno]);
send_buffer( dbgrp, Sim_Reg_Value_Rtnd, 0);
return;
}
DBGRD( printf("read register %d : %s = 0x%llx\n",regno,gdb_reg_name[regno],val););
put_uint64(dbgrp->send_ptr, val);
send_buffer( dbgrp, Sim_Reg_Value_Rtnd, 8);
}
static void if_write_register(debugger_t * dbgrp)
{
int regno;
uint64_t val;
regno = (dbgrp->recv_ptr[0]<<8) | dbgrp->recv_ptr[1];
val = get_uint64(dbgrp->recv_ptr + 2);
DBGRD( printf("write register %d : %s = 0x%llx\n",regno,gdb_reg_name[regno],val););
if (!dbgrp->config_procp->proc_typep->regwrite(dbgrp->pspecp, gdb_reg_map[regno], val)) {
warning("Register %d [%s] write failed", regno, gdb_reg_name[regno]);
}
send_buffer( dbgrp, Sim_Reg_Written, 0);
}
static void if_set_breakpoint(debugger_t * dbgrp)
{
uint64_t val;
val = get_uint64(dbgrp->recv_ptr);
DBGRD( printf("set breakpoint @ 0x%llx\n",val););
dbgrp->config_procp->proc_typep->dbgr_set_break(dbgrp->pspecp, val);
send_buffer( dbgrp, Sim_Breakpoint_Set, 0);
}
static void if_clear_breakpoint(debugger_t * dbgrp)
{
uint64_t val;
val = get_uint64(dbgrp->recv_ptr);
DBGRD( printf("clear breakpoint @ 0x%llx\n",val););
dbgrp->config_procp->proc_typep->dbgr_clear_break(dbgrp->pspecp, val);
send_buffer( dbgrp, Sim_Breakpoint_Cleared, 0);
}
static void if_read_memory(debugger_t * dbgrp)
{
tvaddr_t vaddr;
uint32_t len, res;
uint64_t slen;
int offset;
int num;
bool_t is_physical_addr;
proc_type_t * ptp;
ptp = dbgrp->config_procp->proc_typep;
vaddr = get_uint64(dbgrp->recv_ptr);
len = get_uint32(dbgrp->recv_ptr + 8);
res = get_uint32(dbgrp->recv_ptr + 12);
is_physical_addr = (res == 1);
DBGRD( printf("read %s memory @ 0x%llx [ 0x%x bytes]\n",
is_physical_addr ? "physical" : "virtual",
vaddr, len););
len = ptp->dbgr_mem_read(dbgrp->pspecp, vaddr, !is_physical_addr,
dbgrp->send_ptr, len);
if (len == 0) {
DBGRD( fprintf(stdout, "Failed reading memory"); );
send_buffer( dbgrp, Sim_Mem_Read_Failed_No_Mem, 0);
return;
}
send_buffer( dbgrp, Sim_Mem_Returned, len);
}
static void if_write_memory(debugger_t * dbgrp)
{
tvaddr_t vaddr;
uint32_t len, res;
int offset;
int num;
uint64_t slen;
bool_t is_physical_addr;
proc_type_t * ptp;
ptp = dbgrp->config_procp->proc_typep;
vaddr = get_uint64(dbgrp->recv_ptr);
len = get_uint32(dbgrp->recv_ptr + 8);
res = get_uint32(dbgrp->recv_ptr + 12);
is_physical_addr = (res == 1);
DBGRD( printf("write %s memory @ 0x%llx [ 0x%x bytes]\n",
is_physical_addr ? "physical" : "virtual",
vaddr, len););
len = ptp->dbgr_mem_write(dbgrp->pspecp, vaddr, !is_physical_addr,
dbgrp->recv_ptr+16, len);
if (len == 0) {
DBGRD( fprintf(stdout, "Failed reading memory"); );
send_buffer( dbgrp, Sim_Mem_Write_Failed_No_Mem, 0);
return;
}
send_buffer( dbgrp, Sim_Mem_Write_OK, 0);
}
static void if_clear_memory(debugger_t * dbgrp)
{
tvaddr_t vaddr;
uint32_t len, res;
int offset;
int num;
uint64_t slen;
bool_t is_physical_addr;
proc_type_t * ptp;
ptp = dbgrp->config_procp->proc_typep;
vaddr = get_uint64(dbgrp->recv_ptr);
len = get_uint32(dbgrp->recv_ptr + 8);
res = get_uint32(dbgrp->recv_ptr + 12);
is_physical_addr = (res == 1);
DBGRD( printf("clear %s memory @ 0x%llx [ 0x%x bytes]\n",
is_physical_addr ? "physical" : "virtual",
vaddr, len););
len = ptp->dbgr_mem_clear(dbgrp->pspecp, vaddr, !is_physical_addr, len);
if (len == 0) {
DBGRD( fprintf(stdout, "Failed clearing memory"); );
send_buffer( dbgrp, Sim_Mem_Clear_Failed_No_Mem, 0);
return;
}
send_buffer( dbgrp, Sim_Mem_Clear_OK, 0);
}
/*
* We enter here with the main program thread
* to wait for user interface connections.
* we never leave this function.
*
* The simulator closes ungracefully using exit()
* to kill its threads ...
*/
void interface_wait()
{
static fd_set comm_channels;
int tcp_attach_socket, res;
struct sockaddr_in tcp_server;
struct sockaddr_in from;
int fromlen;
int skt;
int fh, length, on=1;
int max_channel;
sigset_t sigs;
struct hostent * hp;
char * froms;
int retry_cnt=0;
sigfillset(&sigs);
pthread_sigmask(SIG_BLOCK, &sigs, NULL);
skt = socket(AF_INET, SOCK_STREAM, 0);
if (skt < 0) fatal("opening stream socket");
/* enable the reuse of this socket if this process dies */
if (setsockopt(skt,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on))<0)
fatal("turning on REUSEADDR");
/* bind it */
retry:;
tcp_server.sin_family = AF_INET;
tcp_server.sin_addr.s_addr = INADDR_ANY;
tcp_server.sin_port = options.accept_port;
if (bind(skt, (struct sockaddr *)&tcp_server, sizeof(tcp_server)) < 0) {
switch (errno) {
case EAGAIN:
goto retry;
case EADDRINUSE:
printf("\nPort %d already in use ", options.accept_port);
/* user specific a port and it's not available, fatal */
if (options.specific_port) {
printf("\n");
fatal("Port %d already in use, try another",
options.accept_port);
}
/* check if we should retry another port */
if (retry_cnt >= options.port_retry_max) {
printf("\n");
fatal("Max no of retries (%d) reached, use -P -or -p ",
options.port_retry_max);
}
/* try the next port */
options.accept_port++;
retry_cnt++;
printf("- trying %d", options.accept_port);
goto retry;
default:
fatal("binding tcp stream socket");
}
}
/* this not necessary */
length = sizeof(tcp_server);
if (getsockname(skt, (struct sockaddr *) &tcp_server, &length)==-1)
fatal("getting socket name");
PRINTF(("\nWaiting for connection on port # %d\n",
ntohs(tcp_server.sin_port)));
listen(skt, MAX_CONNECTIONS);
tcp_attach_socket = skt;
max_channel = tcp_attach_socket;
FD_ZERO(&comm_channels);
FD_SET(tcp_attach_socket, &comm_channels);
/*
* Wait for a control connection
*/
do {
debugger_t * dbgrp;
res = select(max_channel+1, &comm_channels, (fd_set*)0, (fd_set*)0, (struct timeval*)0 /* stall */);
if (res<0) fatal("select");
/*
* accept the connection
*/
fromlen = sizeof(from);
fh = accept(tcp_attach_socket,(struct sockaddr *)&from, (int*)&fromlen);
hp = gethostbyaddr((char *)&from.sin_addr, 4, AF_INET);
if (hp == (struct hostent *)0) {
froms = inet_ntoa(from.sin_addr);
fprintf(stderr,"cant resolve hostname for %s\n", froms);;
} else {
froms = hp->h_name;
}
fprintf(stderr,"connection from %s : port %d\n", froms, from.sin_port);
/*
* Create the thread to handle this debugger
* connection. It cleans up after itself
* if anything goes wrong.
*/
dbgrp = Xcalloc(1, debugger_t);
dbgrp->socket = fh;
dbgrp->state = DS_unattached;
pthread_mutex_init(&dbgrp->stop_lock, NULL);
pthread_cond_init(&dbgrp->stop_cv, NULL);
callback_register(CB_Breakpoint, dbgrif_stop_cb, (void *)dbgrp);
create_thread(dbgrif, (void*)dbgrp, &dbgrp->pthread_id);
} while (1);
}
#if 0 /* { */
/*
* These functions are called, not from the debugger IF thread,
* but from the simulation execution thread. It is a callback
* notification to the debugger - during simulation to load
* a new symbol table file.
*/
void remdeb_symtab_add_callback(sym_file_t * sym_filep)
{
if (flag_remdeb_if) {
DBGRD( printf("load symtab %s\n",sym_filep->namep););
dbgr.exec_state = Exec_symtab_load;
assert( dbgr.sym_filep == (sym_file_t *)0);
dbgr.sym_filep = sym_filep;
stop_cmd((char*)0, dbgr.cmd_ptr);
}
}
#endif /* } */
#if 0
/* Delete a block of symbols (object file)
*/
void remdeb_symtab_delete_callback(uint64_t symtab_id)
{
if (flag_remdeb_if) {
DBGRD( printf("delete symtab 0x%llx\n",symtab_id););
}
}
/* Change the offset on a block of symbols ...
*/
void remdeb_symtab_offset_callback(uint64_t symtab_id, uint64_t offset, char * sectp)
{
if (flag_remdeb_if) {
DBGRD( printf("change symtab 0x%llx : section [%s] offset 0x%llx\n",symtab_id, sectp ? sectp : "(NULL)", offset););
}
}
#endif
/*
* basic IO routines to help
*/
static int send_buffer(debugger_t * dbgrp, protocol_t cmd, int num)
{
int res;
dbgrp->send_buffer_p[0] = num >> 8;
dbgrp->send_buffer_p[1] = num & 0xff;
dbgrp->send_buffer_p[2] = (unsigned char) cmd;
res = write(dbgrp->socket, dbgrp->send_buffer_p, 3+num);
return (res != 3+num) ? -1 : 0;
}
static protocol_t recv_buffer(debugger_t * dbgrp, int * nrecvdp)
{
int len, num;
len = do_recv(dbgrp->socket, dbgrp->recv_buffer_p, 3);
if (len != 3) return Receive_error;
len = dbgrp->recv_buffer_p[1] + (dbgrp->recv_buffer_p[0]<<8); /* big endian network order */
num = do_recv(dbgrp->socket, dbgrp->recv_ptr, len);
if (num != len) return Receive_error;
if (nrecvdp != (void*)0) *nrecvdp = num;
return (protocol_t)dbgrp->recv_buffer_p[2];
}
static int do_recv(int skt, unsigned char * ptr, int expect)
{
int idx, num;
for (idx=0; idx<expect; idx+=num) {
num = read(skt, ptr + idx, expect-idx);
if (num<0) return -1;
}
return idx;
}
static uint16_t get_uint16(uint8_t * bp)
{
uint16_t val;
val = (uint16_t)bp[0];
val = (val<<8) | (uint16_t)bp[1];
return val;
}
static uint32_t get_uint32(uint8_t * bp)
{
uint32_t val;
val = (uint32_t)bp[0];
val = (val<<8) | (uint32_t)bp[1];
val = (val<<8) | (uint32_t)bp[2];
val = (val<<8) | (uint32_t)bp[3];
return val;
}
static uint64_t get_uint64(uint8_t * bp)
{
uint64_t val;
val = (uint64_t)bp[0];
val = (val<<8) | (uint64_t)bp[1];
val = (val<<8) | (uint64_t)bp[2];
val = (val<<8) | (uint64_t)bp[3];
val = (val<<8) | (uint64_t)bp[4];
val = (val<<8) | (uint64_t)bp[5];
val = (val<<8) | (uint64_t)bp[6];
val = (val<<8) | (uint64_t)bp[7];
return val;
}
static void put_uint16(uint8_t * bp, uint16_t val)
{
bp[0] = (uint8_t)(val >> 8);
bp[1] = (uint8_t)(val);
}
static void put_uint32(uint8_t * bp, uint32_t val)
{
bp[0] = (uint8_t)(val >> 24);
bp[1] = (uint8_t)(val >> 16);
bp[2] = (uint8_t)(val >> 8);
bp[3] = (uint8_t)(val);
}
static void put_uint64(uint8_t * bp, uint64_t val)
{
bp[0] = (uint8_t)(val >> 56);
bp[1] = (uint8_t)(val >> 48);
bp[2] = (uint8_t)(val >> 40);
bp[3] = (uint8_t)(val >> 32);
bp[4] = (uint8_t)(val >> 24);
bp[5] = (uint8_t)(val >> 16);
bp[6] = (uint8_t)(val >> 8);
bp[7] = (uint8_t)(val);
}