📄 mips-stub.c
字号:
{ /* wait around for the start character, ignore all other characters */ while ((ch = getDebugChar ()) != '$'); checksum = 0; xmitcsum = -1; count = 0; /* now, read until a # or end of buffer is found */ while ( (count < BUFMAX-1) && ((ch = getDebugChar ()) != '#') ) checksum += (buffer[count++] = ch); /* make sure that the buffer is null-terminated */ buffer[count] = '\0'; if (ch == '#') { xmitcsum = hex (getDebugChar ()) << 4; xmitcsum += hex (getDebugChar ()); if (checksum != xmitcsum) putDebugChar ('-'); /* failed checksum */ else { putDebugChar ('+'); /* successful transfer */ /* if a sequence char is present, reply the sequence ID */ if (buffer[2] == ':') { putDebugChar (buffer[0]); putDebugChar (buffer[1]); /* remove sequence chars from buffer */ for (i = 3; i <= count; i++) buffer[i - 3] = buffer[i]; } } } } while (checksum != xmitcsum);}/* * Get a positive/negative acknowledgment for a transmitted packet. */static chargetAck (void){ char c; do { c = getDebugChar (); } while ((c != '+') && (c != '-')); return c;}/* * Send the packet in buffer and wait for a positive acknowledgement. */static voidputpacket (char *buffer){ int checksum; /* $<packet info>#<checksum> */ do { char *src = buffer; putDebugChar ('$'); checksum = 0; while (*src != '\0') { int runlen = 0; /* Do run length encoding */ while ((src[runlen] == src[0]) && (runlen < 99)) runlen++; if (runlen > 3) { int encode; /* Got a useful amount */ putDebugChar (*src); checksum += *src; putDebugChar ('*'); checksum += '*'; checksum += (encode = (runlen - 4) + ' '); putDebugChar (encode); src += runlen; } else { putDebugChar (*src); checksum += *src; src++; } } putDebugChar ('#'); putDebugChar (highhex (checksum)); putDebugChar (lowhex (checksum)); } while (getAck () != '+');}/* * Saved instruction data for single step support */static struct { unsigned *targetAddr; unsigned savedInstr; }instrBuffer;/* * If a step breakpoint was planted restore the saved instruction. */static voidundoSStep (void){ if (instrBuffer.targetAddr != NULL) { *instrBuffer.targetAddr = instrBuffer.savedInstr; instrBuffer.targetAddr = NULL; } instrBuffer.savedInstr = NOP_INSTR;}/* * If a single step is requested put a temporary breakpoint at the instruction * which logically follows the next one to be executed. If the next instruction * is a branch instruction then skip the instruction in the delay slot. NOTE: * ERET instructions are NOT handled, as it is impossible to single-step through * the exit code in an exception handler. In addition, no attempt is made to * do anything about BC0T and BC0F, since a condition bit for coprocessor 0 * is not defined on the R4600. Finally, BC2T and BC2F are ignored since there * is no coprocessor 2 on a 4600. */static voiddoSStep (void){ InstFmt inst; instrBuffer.targetAddr = (unsigned *)(registers[PC]+4); /* set default */ inst.word = *(unsigned *)registers[PC]; /* read the next instruction */ switch (inst.RType.op) { /* override default if branch */ case OP_SPECIAL: switch (inst.RType.func) { case OP_JR: case OP_JALR: instrBuffer.targetAddr = (unsigned *)registers[inst.RType.rs]; break; }; break; case OP_REGIMM: switch (inst.IType.rt) { case OP_BLTZ: case OP_BLTZL: case OP_BLTZAL: case OP_BLTZALL: if (registers[inst.IType.rs] < 0 ) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; case OP_BGEZ: case OP_BGEZL: case OP_BGEZAL: case OP_BGEZALL: if (registers[inst.IType.rs] >= 0 ) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; }; break; case OP_J: case OP_JAL: instrBuffer.targetAddr = (unsigned *)((inst.JType.target<<2) + ((registers[PC]+4)&0xf0000000)); break; case OP_BEQ: case OP_BEQL: if (registers[inst.IType.rs] == registers[inst.IType.rt]) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; case OP_BNE: case OP_BNEL: if (registers[inst.IType.rs] != registers[inst.IType.rt]) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; case OP_BLEZ: case OP_BLEZL: if (registers[inst.IType.rs] <= 0) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; case OP_BGTZ: case OP_BGTZL: if (registers[inst.IType.rs] > 0) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; case OP_COP1: if (inst.RType.rs == OP_BC) switch (inst.RType.rt) { case COPz_BCF: case COPz_BCFL: if (registers[FCSR] & CSR_C) instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); else instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); break; case COPz_BCT: case COPz_BCTL: if (registers[FCSR] & CSR_C) instrBuffer.targetAddr = (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4)); else instrBuffer.targetAddr = (unsigned*)(registers[PC]+8); break; }; break; } if( is_steppable((unsigned)instrBuffer.targetAddr) && *(instrBuffer.targetAddr) != BREAK_INSTR ) { instrBuffer.savedInstr = *instrBuffer.targetAddr; *instrBuffer.targetAddr = BREAK_INSTR; } else { instrBuffer.targetAddr = NULL; instrBuffer.savedInstr = NOP_INSTR; } return;}/* * Translate the R4600 exception code into a Unix-compatible signal. */static intcomputeSignal (void){ int exceptionCode = (registers[CAUSE] & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT; switch (exceptionCode) { case EXC_INT: /* External interrupt */ return SIGINT; case EXC_RI: /* Reserved instruction */ case EXC_CPU: /* Coprocessor unusable */ return SIGILL; case EXC_BP: /* Break point */ return SIGTRAP; case EXC_OVF: /* Arithmetic overflow */ case EXC_TRAP: /* Trap exception */ case EXC_FPE: /* Floating Point Exception */ return SIGFPE; case EXC_IBE: /* Bus error (Ifetch) */ case EXC_DBE: /* Bus error (data load or store) */ return SIGBUS; case EXC_MOD: /* TLB modification exception */ case EXC_TLBL: /* TLB miss (Load or Ifetch) */ case EXC_TLBS: /* TLB miss (Store) */ case EXC_ADEL: /* Address error (Load or Ifetch) */ case EXC_ADES: /* Address error (Store) */ return SIGSEGV; case EXC_SYS: /* System call */ return SIGSYS; default: return SIGTERM; }}/* * This support function prepares and sends the message containing the * basic information about this exception. */void gdb_stub_report_exception_info( rtems_vector_number vector, CPU_Interrupt_frame *frame, int thread){ char *optr; int sigval; optr = outBuffer; *optr++ = 'T'; sigval = computeSignal (); *optr++ = highhex (sigval); *optr++ = lowhex (sigval); *optr++ = highhex(SP); /*gdb_hexchars[SP]; */ *optr++ = lowhex(SP); *optr++ = ':'; optr = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ ); *optr++ = ';'; *optr++ = highhex(PC); /*gdb_hexchars[PC]; */ *optr++ = lowhex(PC); *optr++ = ':'; optr = mem2hstr(optr, (unsigned char *)&frame->epc, R_SZ ); *optr++ = ';';#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) if (do_threads) { *optr++ = 't'; *optr++ = 'h'; *optr++ = 'r'; *optr++ = 'e'; *optr++ = 'a'; *optr++ = 'd'; *optr++ = ':'; optr = thread2vhstr(optr, thread); *optr++ = ';'; }#endif *optr++ = '\0';}/* * Scratch frame used to retrieve contexts for different threads, so as * not to disrupt our current context on the stack */CPU_Interrupt_frame current_thread_registers;/* * This function handles all exceptions. It only does two things: * it figures out why it was activated and tells gdb, and then it * reacts to gdb's requests. */void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame){ int host_has_detached = 0; int regno, addr, length; char *ptr; int current_thread; /* current generic thread */ int thread; /* stopped thread: context exception happened in */ long long regval; void *regptr; int binary; registers = (mips_register_t *)frame; thread = 0;#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) if (do_threads) { thread = rtems_gdb_stub_get_current_thread(); }#endif current_thread = thread; { /* reapply all breakpoints regardless of how we came in */ struct z0break *z0, *zother; for (zother=z0break_list; zother!=NULL; zother=zother->next) { if( zother->instr == 0xffffffff ) { /* grab the instruction */ zother->instr = *(zother->address); /* and insert the breakpoint */ *(zother->address) = BREAK_INSTR; } } /* see if we're coming from a breakpoint */ if( *((unsigned *)frame->epc) == BREAK_INSTR ) { /* see if its one of our zbreaks */ for (z0=z0break_list; z0!=NULL; z0=z0->next) { if( (unsigned)z0->address == frame->epc) break; } if( z0 ) { /* restore the original instruction */ *(z0->address) = z0->instr; /* flag the breakpoint */ z0->instr = 0xffffffff; /* now when we return, we'll execute the original code in the original state. This leaves our breakpoint inactive since the break instruction isn't there, but we'll reapply it the next time we come in via step or breakpoint */ } else { /* not a zbreak, see if its our trusty stepping code */ /* * Restore the saved instruction at * the single-step target address. */ undoSStep(); } } } /* reply to host that an exception has occurred with some basic info */ gdb_stub_report_exception_info(vector, frame, thread); putpacket (outBuffer); while (!(host_has_detached)) { outBuffer[0] = '\0'; getpacket (inBuffer); binary = 0; switch (inBuffer[0]) { case '?': gdb_stub_report_exception_info(vector, frame, thread); break; case 'd': /* toggle debug flag */ /* can print ill-formed commands in valid packets & checksum errors */ break; case 'D': /* remote system is detaching - return OK and exit from debugger */ strcpy (outBuffer, "OK"); host_has_detached = 1; break; case 'g': /* return the values of the CPU registers */ regptr = registers;#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) if (do_threads && current_thread != thread ) regptr = ¤t_thread_registers;#endif mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer); break; case 'G': /* set the values of the CPU registers - return OK */ regptr = registers;#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) if (do_threads && current_thread != thread ) regptr = ¤t_thread_registers;#endif if (hex2mem (&inBuffer[1], regptr, NUM_REGS * (sizeof registers))) strcpy (outBuffer, "OK"); else strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */ break; case 'P': /* Pn...=r... Write register n... with value r... - return OK */ ptr = &inBuffer[1]; if (hexToInt(&ptr, ®no) && *ptr++ == '=' && hexToLongLong(&ptr, ®val)) { registers[regno] = regval; strcpy (outBuffer, "OK"); } else strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */ break; case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ ptr = &inBuffer[1]; if (hexToInt (&ptr, &addr) && *ptr++ == ',' && hexToInt (&ptr, &length) && is_readable (addr, length) && (length < (BUFMAX - 4)/2)) mem2hex ((void *)addr, length, outBuffer); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -