#include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "realthing.h" typedef struct ms MS; struct ms { uint32_t instr; uint32_t regs[32]; uint32_t y; unsigned int cc; } ; #define BLOBSIZE ((33*4)+1) static const char * const regnames[] = { "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", "%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 NBUFS 8 static int fd = -1; static char *conntext; static int fd_af; static int fd_st; static int fd_proto; static struct sockaddr *fd_sa; static socklen_t fd_salen; static MS prestate; static MS poststate; static MS realstate; static int pid; static void set4(unsigned char *buf, uint32_t v) { buf[0] = v >> 24; buf[1] = (v >> 16) & 0xff; buf[2] = (v >> 8) & 0xff; buf[3] = v & 0xff; } static uint32_t get4(const unsigned char *buf) { return( (buf[0] * 0x01000000) | (buf[1] * 0x00010000) | (buf[2] * 0x00000100) | (buf[3] * 0x00000001) ); } static void encode_state(unsigned char *buf, const MS *s) { int i; for (i=32-1;i>=0;i--) set4(buf+(i*4),s->regs[i]); set4(buf+(32*4),s->y); buf[33*4] = s->cc; } static void decode_state(const unsigned char *buf, MS *s) { int i; for (i=32-1;i>=0;i--) s->regs[i] = get4(buf+(i*4)); s->y = get4(buf+(32*4)); s->cc = buf[33*4]; } static const char *cc_string(unsigned int cc) { static char obuf[NBUFS][8]; static int hand = 0; char *b; b = &obuf[hand][0]; hand --; if (hand < 0) hand = NBUFS - 1; b[0] = (cc & 8) ? 'N' : '-'; b[1] = (cc & 4) ? 'Z' : '-'; b[2] = (cc & 2) ? 'V' : '-'; b[3] = (cc & 1) ? 'C' : '-'; b[4] = '\0'; return(b); } void realthing_setup(const char *arg) { int s; const char *slash; char *h; const char *p; int e; struct addrinfo hints; struct addrinfo *ai0; struct addrinfo *ai; char hn[NI_MAXHOST]; char sn[NI_MAXSERV]; int o; slash = index(arg,'/'); if (! slash) { fprintf(stderr,"%s: no slash in `%s'\n",__progname,arg); exit(1); } h = malloc((slash-arg)+1); bcopy(arg,h,slash-arg); h[slash-arg] = '\0'; p = slash + 1; hints.ai_flags = 0; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; // next four assignments: XXX API botch hints.ai_addrlen = 0; hints.ai_canonname = 0; hints.ai_addr = 0; hints.ai_next = 0; e = getaddrinfo(h,p,&hints,&ai0); if (e) { fprintf(stderr,"%s: %s/%s: %s\n",__progname,h,p,gai_strerror(e)); exit(1); } if (! ai0) { fprintf(stderr,"%s: %s/%s: getaddrinfo succeeded but no addresses?\n",__progname,h,p); exit(1); } do <"connected"> { for (ai=ai0;ai;ai=ai->ai_next) { e = getnameinfo(ai->ai_addr,ai->ai_addrlen,&hn[0],NI_MAXHOST,&sn[0],NI_MAXSERV,NI_NUMERICHOST|NI_NUMERICSERV); if (e) { fprintf(stderr,"%s: %s/%s: AF %d: getnameinfo failed %d: %s\n",__progname,h,p,ai->ai_addr->sa_family,e,gai_strerror(e)); continue; } s = socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol); if (s < 0) { fprintf(stderr,"%s: %s/%s: socket: %s\n",__progname,&hn[0],&sn[0],strerror(errno)); continue; } if (connect(s,ai->ai_addr,ai->ai_addrlen) < 0) { fprintf(stderr,"%s: %s/%s: connect: %s\n",__progname,&hn[0],&sn[0],strerror(errno)); close(s); continue; } break <"connected">; } exit(1); } while (0); fd = s; o = 1; setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,&o,sizeof(o)); asprintf(&conntext,"%s/%s",&hn[0],&sn[0]); fd_af = ai->ai_family; fd_st = ai->ai_socktype; fd_proto = ai->ai_protocol; fd_salen = ai->ai_addrlen; fd_sa = malloc(fd_salen); bcopy(ai->ai_addr,fd_sa,fd_salen); freeaddrinfo(ai0); pid = getpid(); } void realthing_pre(uint32_t inst, const uint32_t *regs, uint32_t y, unsigned int cc) { unsigned char obuf[4+BLOBSIZE]; int o; int n; if (fd < 0) return; if (pid != getpid()) { int o; close(fd); fd = socket(fd_af,fd_st,fd_proto); if (fd < 0) { fprintf(stderr,"%s: %s: socket: %s\n",__progname,conntext,strerror(errno)); return; } if (connect(fd,fd_sa,fd_salen) < 0) { fprintf(stderr,"%s: %s: connect: %s\n",__progname,conntext,strerror(errno)); close(fd); fd = -1; return; } o = 1; setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,&o,sizeof(o)); pid = getpid(); } prestate.instr = inst; bcopy(regs,&prestate.regs[0],32*sizeof(uint32_t)); prestate.y = y; prestate.cc = cc; set4(&obuf[0],inst); encode_state(&obuf[4],&prestate); o = 0; while (o < 4+BLOBSIZE) { n = write(fd,&obuf[0],4+BLOBSIZE-o); if (n < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: realthing write: %s\n",__progname,strerror(errno)); exit(1); } o += n; } } void realthing_post(const uint32_t *regs, uint32_t y, unsigned int cc) { unsigned char ibuf[BLOBSIZE]; int n; int o; int i; if (fd < 0) return; bcopy(regs,&poststate.regs[0],32*sizeof(uint32_t)); poststate.y = y; poststate.cc = cc; // Compensate for the way %g0 is implemented in user.c poststate.regs[0] = 0; o = 0; while (o < BLOBSIZE) { n = read(fd,&ibuf[o],BLOBSIZE-o); if (n < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: realthing read: %s\n",__progname,strerror(errno)); exit(1); } if (n == 0) { fprintf(stderr,"%s: realthing read got unexpected EOF\n",__progname); exit(1); } o += n; } decode_state(&ibuf[0],&realstate); do <"diff"> { if (realstate.cc != poststate.cc) break <"diff">; if (realstate.y != poststate.y) break <"diff">; for (i=0;i<32;i++) if (realstate.regs[i] != poststate.regs[i]) break <"diff">; return; } while (0); printf("Instruction %08x\n",(unsigned int)prestate.instr); printf("\t\tPre\t\tPost\t\tReal\n"); if (! ((prestate.cc == poststate.cc) && (realstate.cc == poststate.cc))) { fprintf(stderr,"cc\t\t%s\t\t%s\t\t%s\n",cc_string(prestate.cc),cc_string(poststate.cc),cc_string(realstate.cc)); } if (! ((prestate.y == poststate.y) && (realstate.y == poststate.y))) { fprintf(stderr,"y\t\t%08lx\t%08lx\t%08lx\n", (unsigned long int)prestate.y, (unsigned long int)poststate.y, (unsigned long int)realstate.y); } for (i=0;i<32;i++) { if (! ((prestate.regs[i] == poststate.regs[i]) && (realstate.regs[i] == poststate.regs[i]))) { fprintf(stderr,"%s\t\t%08lx\t%08lx\t%08lx\n", regnames[i], (unsigned long int)prestate.regs[i], (unsigned long int)poststate.regs[i], (unsigned long int)realstate.regs[i]); } } exit(1); }