mirror of
https://github.com/simh/simh.git
synced 2026-01-26 04:01:38 +00:00
FRONTPANEL: Added better protocol debug support to debug simulator startup issues
This commit is contained in:
160
sim_frontpanel.c
160
sim_frontpanel.c
@@ -188,84 +188,98 @@ static unsigned char mantra[] = {
|
||||
TN_IAC, TN_DO, TN_BIN
|
||||
};
|
||||
|
||||
static void *
|
||||
_panel_malloc (size_t size)
|
||||
{
|
||||
void *p = malloc (size);
|
||||
|
||||
if (p == NULL)
|
||||
sim_panel_set_error ("Out of Memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
static void _panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...)
|
||||
{
|
||||
if (p && p->Debug && (dbits & p->debug)) {
|
||||
int i;
|
||||
struct timespec time_now;
|
||||
va_list arglist;
|
||||
char timestamp[32];
|
||||
size_t obufsize = 10240 + 8*bufsize;
|
||||
char *obuf = (char *)_panel_malloc (obufsize);
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &time_now);
|
||||
fprintf(p->Debug, "%lld.%03d ", (long long)(time_now.tv_sec), (int)(time_now.tv_nsec/1000000));
|
||||
sprintf (timestamp, "%lld.%03d ", (long long)(time_now.tv_sec), (int)(time_now.tv_nsec/1000000));
|
||||
|
||||
va_start (arglist, bufsize);
|
||||
vfprintf (p->Debug, fmt, arglist);
|
||||
vsnprintf (obuf, obufsize - 1, fmt, arglist);
|
||||
va_end (arglist);
|
||||
|
||||
|
||||
for (i=0; i<bufsize; ++i) {
|
||||
switch ((unsigned char)buf[i]) {
|
||||
case TN_CR:
|
||||
fprintf(p->Debug, "_TN_CR_");
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_CR_");
|
||||
break;
|
||||
case TN_LF:
|
||||
fprintf(p->Debug, "_TN_LF_");
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_LF_");
|
||||
break;
|
||||
case TN_IAC:
|
||||
fprintf(p->Debug, "_TN_IAC_");
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_IAC_");
|
||||
switch ((unsigned char)buf[i+1]) {
|
||||
case TN_IAC:
|
||||
fprintf(p->Debug, "_TN_IAC_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_IAC_"); ++i;
|
||||
break;
|
||||
case TN_DONT:
|
||||
fprintf(p->Debug, "_TN_DONT_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_DONT_"); ++i;
|
||||
break;
|
||||
case TN_DO:
|
||||
fprintf(p->Debug, "_TN_DO_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_DO_"); ++i;
|
||||
break;
|
||||
case TN_WONT:
|
||||
fprintf(p->Debug, "_TN_WONT_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_WONT_"); ++i;
|
||||
break;
|
||||
case TN_WILL:
|
||||
fprintf(p->Debug, "_TN_WILL_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_WILL_"); ++i;
|
||||
break;
|
||||
default:
|
||||
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_0x%02X_", (unsigned char)buf[i+1]); ++i;
|
||||
break;
|
||||
}
|
||||
switch ((unsigned char)buf[i+1]) {
|
||||
case TN_BIN:
|
||||
fprintf(p->Debug, "_TN_BIN_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_BIN_"); ++i;
|
||||
break;
|
||||
case TN_ECHO:
|
||||
fprintf(p->Debug, "_TN_ECHO_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_ECHO_"); ++i;
|
||||
break;
|
||||
case TN_SGA:
|
||||
fprintf(p->Debug, "_TN_SGA_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_SGA_"); ++i;
|
||||
break;
|
||||
case TN_LINE:
|
||||
fprintf(p->Debug, "_TN_LINE_"); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_TN_LINE_"); ++i;
|
||||
break;
|
||||
default:
|
||||
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i;
|
||||
sprintf (&obuf[strlen (obuf)], "_0x%02X_", (unsigned char)buf[i+1]); ++i;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (isprint((u_char)buf[i]))
|
||||
fprintf(p->Debug, "%c", buf[i]);
|
||||
sprintf (&obuf[strlen (obuf)], "%c", buf[i]);
|
||||
else {
|
||||
fprintf(p->Debug, "_");
|
||||
sprintf (&obuf[strlen (obuf)], "_");
|
||||
if ((buf[i] >= 1) && (buf[i] <= 26))
|
||||
fprintf(p->Debug, "^%c", 'A' + buf[i] - 1);
|
||||
sprintf (&obuf[strlen (obuf)], "^%c", 'A' + buf[i] - 1);
|
||||
else
|
||||
fprintf(p->Debug, "\\%03o", (u_char)buf[i]);
|
||||
fprintf(p->Debug, "_");
|
||||
sprintf (&obuf[strlen (obuf)], "\\%03o", (u_char)buf[i]);
|
||||
sprintf (&obuf[strlen (obuf)], "_");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(p->Debug, "\n");
|
||||
fprintf(p->Debug, "%s%s\n", timestamp, obuf);
|
||||
free (obuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,16 +308,6 @@ if (panel->Debug)
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
_panel_malloc (size_t size)
|
||||
{
|
||||
void *p = malloc (size);
|
||||
|
||||
if (p == NULL)
|
||||
sim_panel_set_error ("Out of Memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
static int
|
||||
_panel_send (PANEL *p, const char *msg, int len)
|
||||
{
|
||||
@@ -446,6 +450,15 @@ sim_panel_start_simulator (const char *sim_path,
|
||||
const char *sim_config,
|
||||
size_t device_panel_count)
|
||||
{
|
||||
return sim_panel_start_simulator_debug (sim_path, sim_config, device_panel_count, NULL);
|
||||
}
|
||||
|
||||
PANEL *
|
||||
sim_panel_start_simulator_debug (const char *sim_path,
|
||||
const char *sim_config,
|
||||
size_t device_panel_count,
|
||||
const char *debug_file)
|
||||
{
|
||||
PANEL *p = NULL;
|
||||
FILE *fIn = NULL;
|
||||
FILE *fOut = NULL;
|
||||
@@ -528,6 +541,11 @@ fprintf (fOut, "set remote -u telnet=%s\n", hostport);
|
||||
fprintf (fOut, "set remote master\n");
|
||||
fclose (fOut);
|
||||
fOut = NULL;
|
||||
if (debug_file) {
|
||||
sim_panel_set_debug_file (p, debug_file);
|
||||
sim_panel_set_debug_mode (p, DBG_XMT|DBG_RCV);
|
||||
_panel_debug (p, DBG_XMT|DBG_RCV, "Creating Simulator Process %s\n", NULL, 0, sim_path);
|
||||
}
|
||||
if (1) {
|
||||
#if defined(_WIN32)
|
||||
char cmd[2048];
|
||||
@@ -553,7 +571,8 @@ if (1) {
|
||||
#else
|
||||
p->pidProcess = fork();
|
||||
if (p->pidProcess == 0) {
|
||||
close (0); close (1); close (2); /* make sure not to pass the open standard handles */
|
||||
close (0); close (1); close (2); /* make sure not to pass the open standard handles */
|
||||
dup (dup (open ("/dev/null", O_RDWR))); /* open standard handles to /dev/null */
|
||||
if (execlp (sim_path, sim_path, p->temp_config, NULL, NULL)) {
|
||||
perror ("execl");
|
||||
exit(errno);
|
||||
@@ -574,17 +593,25 @@ for (i=0; i<100; i++) { /* Allow up to 10 seconds waiting for simulator
|
||||
break;
|
||||
}
|
||||
if (p->sock == INVALID_SOCKET) {
|
||||
sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", hostport);
|
||||
if (stat (sim_path, &statb) < 0)
|
||||
sim_panel_set_error ("Can't stat simulator '%s': %s", sim_path, strerror(errno));
|
||||
else
|
||||
sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", hostport);
|
||||
goto Error_Return;
|
||||
}
|
||||
strcpy (p->hostport, hostport);
|
||||
_panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator at %s after %dms\n", NULL, 0, hostport, i*100);
|
||||
pthread_mutex_init (&p->io_lock, NULL);
|
||||
pthread_mutex_init (&p->io_send_lock, NULL);
|
||||
pthread_cond_init (&p->io_done, NULL);
|
||||
pthread_cond_init (&p->startup_cond, NULL);
|
||||
if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) {
|
||||
sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
|
||||
goto Error_Return;
|
||||
}
|
||||
if (1) {
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_mutex_init (&p->io_lock, NULL);
|
||||
pthread_mutex_init (&p->io_send_lock, NULL);
|
||||
pthread_cond_init (&p->io_done, NULL);
|
||||
pthread_cond_init (&p->startup_cond, NULL);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_mutex_lock (&p->io_lock);
|
||||
@@ -595,10 +622,6 @@ if (1) {
|
||||
pthread_mutex_unlock (&p->io_lock);
|
||||
pthread_cond_destroy (&p->startup_cond);
|
||||
}
|
||||
if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) {
|
||||
sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
|
||||
goto Error_Return;
|
||||
}
|
||||
if (device_panel_count) {
|
||||
p->devices = (PANEL **)_panel_malloc (device_panel_count*sizeof(*p->devices));
|
||||
if (p->devices == NULL)
|
||||
@@ -606,8 +629,7 @@ if (device_panel_count) {
|
||||
memset (p->devices, 0, device_panel_count*sizeof(*p->devices));
|
||||
p->device_count = device_panel_count;
|
||||
}
|
||||
msleep (1000);
|
||||
/* Validate existence of requested register */
|
||||
/* Validate sim_frontpanel API version */
|
||||
if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) {
|
||||
goto Error_Return;
|
||||
}
|
||||
@@ -634,7 +656,15 @@ if (fOut) {
|
||||
}
|
||||
if (buf)
|
||||
free (buf);
|
||||
sim_panel_destroy (p);
|
||||
if (1) {
|
||||
const char *err = sim_panel_get_error();
|
||||
char *errbuf = (char *)_panel_malloc (1 + strlen (err));
|
||||
|
||||
strcpy (errbuf, err); /* preserve error info while closing */
|
||||
sim_panel_destroy (p);
|
||||
sim_panel_set_error ("%s", errbuf);
|
||||
free (errbuf);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -666,7 +696,7 @@ if (p->device_name == NULL)
|
||||
strcpy (p->device_name, device_name);
|
||||
p->parent = simulator_panel;
|
||||
p->sock = INVALID_SOCKET;
|
||||
for (i=0; i<5; i++) {
|
||||
for (i=0; i<100; i++) {
|
||||
p->sock = sim_connect_sock_ex (NULL, simulator_panel->hostport, NULL, NULL, SIM_SOCK_OPT_NODELAY | SIM_SOCK_OPT_BLOCKING);
|
||||
if (p->sock == INVALID_SOCKET)
|
||||
msleep (100);
|
||||
@@ -678,13 +708,17 @@ if (p->sock == INVALID_SOCKET) {
|
||||
goto Error_Return;
|
||||
}
|
||||
strcpy (p->hostport, simulator_panel->hostport);
|
||||
pthread_mutex_init (&p->io_lock, NULL);
|
||||
pthread_mutex_init (&p->io_send_lock, NULL);
|
||||
pthread_cond_init (&p->io_done, NULL);
|
||||
pthread_cond_init (&p->startup_cond, NULL);
|
||||
if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) {
|
||||
sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
|
||||
goto Error_Return;
|
||||
}
|
||||
if (1) {
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_mutex_init (&p->io_lock, NULL);
|
||||
pthread_mutex_init (&p->io_send_lock, NULL);
|
||||
pthread_cond_init (&p->io_done, NULL);
|
||||
pthread_cond_init (&p->startup_cond, NULL);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
pthread_mutex_lock (&p->io_lock);
|
||||
@@ -695,10 +729,6 @@ if (1) {
|
||||
pthread_mutex_unlock (&p->io_lock);
|
||||
pthread_cond_destroy (&p->startup_cond);
|
||||
}
|
||||
if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) {
|
||||
sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
|
||||
goto Error_Return;
|
||||
}
|
||||
simulator_panel->devices[device_num] = p;
|
||||
_panel_register_panel (p);
|
||||
return p;
|
||||
@@ -1069,6 +1099,28 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
|
||||
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||
|
||||
pthread_mutex_lock (&p->io_lock);
|
||||
if (!p->parent) {
|
||||
while (1) {
|
||||
int new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
|
||||
|
||||
if (new_data <= 0) {
|
||||
sim_panel_set_error ("%s", sim_get_err_sock("Unexpected socket read"));
|
||||
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
|
||||
p->State = Error;
|
||||
break;
|
||||
}
|
||||
_panel_debug (p, DBG_RCV, "Startup receive of %d bytes: ", &buf[buf_data], new_data, new_data);
|
||||
buf_data += new_data;
|
||||
buf[buf_data] = '\0';
|
||||
if ((size_t)buf_data < strlen (sim_prompt))
|
||||
continue;
|
||||
if (!strcmp (sim_prompt, &buf[buf_data - strlen (sim_prompt)])) {
|
||||
memmove (buf, &buf[buf_data - strlen (sim_prompt)], strlen (sim_prompt) + 1);
|
||||
buf_data = strlen (sim_prompt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
p->io_thread_running = 1;
|
||||
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
|
||||
while ((p->sock != INVALID_SOCKET) &&
|
||||
|
||||
Reference in New Issue
Block a user