/* $Id$ */ #define DEBUGGEE #include "message.h" #define MAXBP 128 #define MAXTRACE 16 static int nbp; /* # of breakpoints */ static char *bp[MAXBP]; static int ntrace; static struct trace { char *begin_trace, *end_trace; } trace_buf[MAXTRACE]; static struct message_hdr ok_message; #define OFF 0 #define SS 1 /* single stepping */ #define SSF 2 /* single stepping, counting functions as single statements */ static char * BUFTOA(p) register char *p; { register long l = 0; register int i; for (i = PS; i>0; i--) { l = (l << 8) | (*p++ & 0377); } return (char *) l; } static long BUFTOL(p) register char *p; { register long l = 0; register int i; for (i = LS; i>0; i--) { l = (l << 8) | (*p++ & 0377); } return l; } static ATOBUF(p, cp) register char *p; char *cp; { register int i; register long l = (long) cp; p += PS; for (i = PS; i > 0; i--) { *--p = l; l >>= 8; } } static LTOBUF(p, l) register char *p; register long l; { register int i; p += LS; for (i = LS; i > 0; i--) { *--p = l; l >>= 8; } } static int single_stepping = OFF; static int db_ss = 0; static int step_count = 0; static char *savedlb; static int break_flag = 0; static int reading = 0; static char *retaddr; static char *LB; static char *currbrk; extern char *__Get_LB(); extern char *__Get_Hol0(); extern char *__Get_PC(); extern char *__Cvt_LB_AB(); extern char *__Get_HP(); extern char *_sbrk(); extern int etext; extern __Set_PC(); static send_ok(); #define check_ptr(c) (((c) >= (char *)&etext && (c) <= currbrk) || (c) >= LB) #define IN_FD 3 #define OUT_FD 6 static int ureceive(p, c) char *p; long c; { int i; int retval = 1; reading = 1; while (c >= 0x1000) { i = _read(IN_FD, p, 0x1000); if (i == 0) return 0; if (i < 0) { retval = 0; c -= 0x1000; } else { p += i; c -= i; } } while (c > 0) { i = _read(IN_FD, p, (int)c); if (i == 0) return 0; if (i < 0) { retval = 0; break; } else { p += i; c -= i; } } reading = 0; return retval; } static int usend(p, c) char *p; long c; { int i; while (c >= 0x1000) { i = _write(OUT_FD, p, 0x1000); if (i < 0) { return 0; } p += i; c -= i; } while (c > 0) { i = _write(OUT_FD, p, (int)c); if (i < 0) { return 0; } p += i; c -= i; } return 1; } static int ugetm(message) struct message_hdr *message; { if (! ureceive((char *) message, (long) sizeof(struct message_hdr))) { return 0; } return 1; } static int uputm(message) struct message_hdr *message; { if (! usend((char *) message, (long) sizeof(struct message_hdr))) { return 0; } return 1; } static int sendreply(m, p, sz) struct message_hdr *m; char *p; long sz; { if (! uputm(m) || ! (sz && p ? usend(p, sz) : 1)) { return 0; } return 1; } static int do_request() { /* obtain a request from the debugger and perform it */ int fail = 0; register int i; register char *c; char *c1; long sz; struct message_hdr message; start: if (! ugetm(&message)) { /* failed to get a message. Something is wrong. Let process continue */ return 1; } if (message.m_type & M_DB_SS) db_ss = 1; message.m_type &= 0177; switch(message.m_type) { case M_OK: /* sometimes sent to child to see if it lives */ goto start; case M_SETBP: /* set a breakpoint */ if (nbp == MAXBP) { fail = 1; break; } bp[nbp++] = BUFTOA(message.m_buf+1); break; case M_SETTRACE: if (ntrace == MAXTRACE) { fail = 1; break; } trace_buf[ntrace].begin_trace = BUFTOA(message.m_buf+1); trace_buf[ntrace++].end_trace = BUFTOA(message.m_buf+(PS+1)); break; case M_CLRBP: i = 0; c = BUFTOA(message.m_buf+1); while (i < nbp && bp[i] != c) { i++; } if (i < nbp) { while (i < nbp) { bp[i] = bp[i+1]; i++; } nbp--; } else { fail = 1; } break; case M_CLRTRACE: i = 0; c = BUFTOA(message.m_buf+1); c1 = BUFTOA(message.m_buf+(PS+1)); while (i < ntrace && trace_buf[i].begin_trace != c && trace_buf[i].end_trace != c1){ i++; } if (i < ntrace) { while (i < ntrace) { trace_buf[i] = trace_buf[i+1]; i++; } ntrace--; } else { fail = 1; } break; case M_SETSS: single_stepping = SS; step_count = BUFTOL(message.m_buf+1); return 1; case M_CLRSS: single_stepping = OFF; break; case M_SETSSF: savedlb = __Get_LB(2); step_count = BUFTOL(message.m_buf+1); single_stepping = SSF; return 1; case M_GETBYTES: message.m_type = M_DATA; sz = BUFTOL(message.m_buf+1); c = BUFTOA(message.m_buf+(LS+1)); currbrk = _sbrk(0); if (! check_ptr(c) || ! check_ptr(c+sz-1)) { fail = 1; break; } return sendreply(&message, c, sz) ? 0 : -1; case M_GETSTR: sz = BUFTOL(message.m_buf+1); c1 = c = BUFTOA(message.m_buf+(LS+1)); currbrk = _sbrk(0); if (check_ptr(c)) { while (*c) { if (c - c1 + 1 >= sz) break; c++; if (! check_ptr(c)) { fail = 1; break; } } } else fail = 1; if (fail) break; message.m_type = M_DATA; sz = c - c1 + 1; LTOBUF(message.m_buf+1, sz); return sendreply(&message, c1, sz) ? 0 : -1; case M_SETBYTES: if (! ureceive(BUFTOA(message.m_buf+(LS+1)), BUFTOL(message.m_buf+1))) { fail = 1; } break; case M_GETEMREGS: i = BUFTOL(message.m_buf+1); c = __Get_LB(i+2); /* local base */ c1 = __Get_LB(i+1); /* needed to find PC and SP */ ATOBUF(message.m_buf+LB_OFF, c); ATOBUF(message.m_buf+AB_OFF, __Cvt_LB_AB(c)); ATOBUF(message.m_buf+PC_OFF, __Get_PC(c1)); ATOBUF(message.m_buf+HP_OFF, __Get_HP()); ATOBUF(message.m_buf+SP_OFF, __Cvt_LB_AB(c1)); return sendreply(&message, (char *) 0, 0L) ? 0 : -1; case M_SETEMREGS: /* actually, only the program counter is settable */ i = BUFTOL(message.m_buf+1); c = __Get_LB(i+1); __Set_PC(c, BUFTOA(message.m_buf+PC_OFF)); break; case M_CONT: return 1; case M_DUMP: currbrk = _sbrk(0); c = __Get_Hol0(); c1 = currbrk; message.m_type = M_DGLOB; sz = c1 - c; LTOBUF(message.m_buf+1, sz); ATOBUF(message.m_buf + HP_OFF, __Get_HP()); ATOBUF(message.m_buf + PC_OFF, __Get_PC(__Get_LB(1))); ATOBUF(message.m_buf + LB_OFF, c1); sendreply(&message, c, sz); if (! ___topsave()) { /* we get here after a ___topload() ! */ step_count = 0; nbp = 0; single_stepping = 0; savedlb = 0; break_flag = 0; db_ss = 0; break; } return 0; case M_DGLOB: _brk(BUFTOA(message.m_buf + LB_OFF)); __Set_HP(BUFTOA(message.m_buf+HP_OFF)); if (! ureceive(__Get_Hol0(), BUFTOL(message.m_buf+1))) {} ___topload(BUFTOA(message.m_buf + SP_OFF)); /*NOTREACHED*/ } send_ok(fail ? M_FAIL : M_OK); return fail ? -1 : 0; } ___sendtop(addr, SP, sz) char *addr, *SP; unsigned sz; { struct message_hdr m; m.m_type = M_DSTACK; LTOBUF(m.m_buf+1, (long) sz); ATOBUF(m.m_buf+SP_OFF, SP); sendreply(&m, addr, (long)sz); } ___restoretop(SP) char *SP; { struct message_hdr m; if (! ugetm(&m)) {} if (! ureceive(SP, BUFTOL(m.m_buf+1))) {} } static sigcatch() { signal(7, sigcatch); if (reading) send_ok(M_INTR); else break_flag = 1; db_ss = 0; } static int check_bp() { register int i; for (i = 0; i < nbp; i++) { if (bp[i] == retaddr) { return 1; } } return 0; } static int check_trace() { register int i; for (i = 0; i < ntrace; i++) { if (trace_buf[i].begin_trace <= retaddr && trace_buf[i].end_trace >= retaddr) { return 1; } } return 0; } static send_ok(type) { register int i; ok_message.m_type = type; LTOBUF(ok_message.m_buf+1, (long) retaddr); uputm(&ok_message); } void __uX_LiB() /* This function must be called after every LIN and LNI */ { int status = M_CONT; LB = __Get_LB(0); if ( retaddr) { /* not the first time ... */ retaddr = __Get_PC(LB); /* first, adjust step_count when single stepping */ if (single_stepping == SS) step_count--; else if (single_stepping == SSF) { char *lb = __Get_LB(1); if (!((char *) &lb < lb && lb >= savedlb || (char *) &lb > lb && lb <= savedlb)) { } else { savedlb = lb; step_count--; } } if (single_stepping != OFF && step_count <= 0) { status = M_END_SS; single_stepping = OFF; } else if (break_flag) status = M_INTR; } else { signal(7, sigcatch); retaddr = __Get_PC(LB); status = M_OK; } if (status == M_CONT) { if ((nbp != 0 && check_bp() != 0) || (ntrace != 0 && check_trace() != 0)) { status = M_OK; } else if (break_flag) status = M_INTR; else { if (db_ss) { db_ss = 0; send_ok(M_DB_SS); while (do_request() <= 0) /* nothing */; } if (break_flag) status = M_INTR; else return; } } break_flag = 0; send_ok(status); db_ss = 0; while (do_request() <= 0) /* nothing */; }