/* convert the hex array pointed to by buf into binary to be placed in mem * return a pointer to the character AFTER the last byte fetched from buf. */ static char * hex2mem(char *buf, char *mem, int count) { int hexValue; char *tmp_raw, *tmp_hex; /* * We use the upper half of buf as an intermediate buffer for the * raw memory that is converted from hex. */ tmp_raw = buf + count * 2; tmp_hex = tmp_raw - 1; longjmp_on_fault = 1; while (tmp_hex >= buf) { tmp_raw--; hexValue = hex(*tmp_hex--); if (hexValue < 0) kgdb_error(KGDBERR_NOTHEXDIG); *tmp_raw = hexValue; hexValue = hex(*tmp_hex--); if (hexValue < 0) kgdb_error(KGDBERR_NOTHEXDIG); *tmp_raw |= hexValue << 4; } memcpy(mem, tmp_raw, count); kgdb_flush_cache_range((void *)mem, (void *)(mem+count)); longjmp_on_fault = 0; return buf; }
void kgdb_putregs(struct pt_regs *regs, char *buf, int length) { unsigned long *gdb_regs = (unsigned long *)buf; if (length < (GDB_MAX_REGS *sizeof(unsigned long))) kgdb_error(KGDBERR_NOSPACE); if ((unsigned long)gdb_regs & 3) kgdb_error(KGDBERR_ALIGNFAULT); regs->ARM_r0 = gdb_regs[_R0]; regs->ARM_r1 = gdb_regs[_R1]; regs->ARM_r2 = gdb_regs[_R2]; regs->ARM_r3 = gdb_regs[_R3]; regs->ARM_r4 = gdb_regs[_R4]; regs->ARM_r5 = gdb_regs[_R5]; regs->ARM_r6 = gdb_regs[_R6]; regs->ARM_r7 = gdb_regs[_R7]; regs->ARM_r8 = gdb_regs[_R8]; regs->ARM_r9 = gdb_regs[_R9]; regs->ARM_r10 = gdb_regs[_R10]; regs->ARM_fp = gdb_regs[_FP]; regs->ARM_ip = gdb_regs[_IP]; regs->ARM_sp = gdb_regs[_SPT]; regs->ARM_lr = gdb_regs[_LR]; regs->ARM_pc = gdb_regs[_PC]; regs->ARM_cpsr = gdb_regs[_CPSR]; }
void kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length) { unsigned long val, *ptr = (unsigned long *)buf; if (regno < 0 || GDB_MAX_REGS <= regno) kgdb_error(KGDBERR_BADPARAMS); else { if (length < 4) kgdb_error(KGDBERR_NOSPACE); } if ((unsigned long)ptr & 3) kgdb_error(KGDBERR_ALIGNFAULT); else val = *ptr; switch (regno) { case _R0: regs->ARM_r0 = val; break; case _R1: regs->ARM_r1 = val; break; case _R2: regs->ARM_r2 = val; break; case _R3: regs->ARM_r3 = val; break; case _R4: regs->ARM_r4 = val; break; case _R5: regs->ARM_r5 = val; break; case _R6: regs->ARM_r6 = val; break; case _R7: regs->ARM_r7 = val; break; case _R8: regs->ARM_r8 = val; break; case _R9: regs->ARM_r9 = val; break; case _R10: regs->ARM_r10 = val; break; case _FP: regs->ARM_fp = val; break; case _IP: regs->ARM_ip = val; break; case _SPT: regs->ARM_sp = val; break; case _LR: regs->ARM_lr = val; break; case _PC: regs->ARM_pc = val; break; case 0x19: regs->ARM_cpsr = val; break; default: kgdb_error(KGDBERR_BADPARAMS); } }
int kgdb_getregs(struct pt_regs *regs, char *buf, int max) { int i; unsigned long *gdb_regs = (unsigned long *)buf; if (max < (GDB_MAX_REGS * sizeof(unsigned long))) kgdb_error(KGDBERR_NOSPACE); /* Initialize all to zero. */ for (i = 0; i < GDB_MAX_REGS; i++) gdb_regs[i] = 0; gdb_regs[_R0] = regs->ARM_r0; gdb_regs[_R1] = regs->ARM_r1; gdb_regs[_R2] = regs->ARM_r2; gdb_regs[_R3] = regs->ARM_r3; gdb_regs[_R4] = regs->ARM_r4; gdb_regs[_R5] = regs->ARM_r5; gdb_regs[_R6] = regs->ARM_r6; gdb_regs[_R7] = regs->ARM_r7; gdb_regs[_R8] = regs->ARM_r8; gdb_regs[_R9] = regs->ARM_r9; gdb_regs[_R10] = regs->ARM_r10; gdb_regs[_FP] = regs->ARM_fp; gdb_regs[_IP] = regs->ARM_ip; gdb_regs[_SPT] = regs->ARM_sp; gdb_regs[_LR] = regs->ARM_lr; gdb_regs[_PC] = regs->ARM_pc; gdb_regs[_CPSR] = regs->ARM_cpsr; return GDB_MAX_REGS *sizeof(unsigned long); }
/* convert the hex array pointed to by buf into binary to be placed in mem * return a pointer to the character AFTER the last byte fetched from buf. */ static char * hex2mem(char *buf, char *mem, int count) { int i, hexValue; unsigned char ch; char *mem_start = mem; longjmp_on_fault = 1; for (i=0; i<count; i++) { if ((hexValue = hex(*buf++)) < 0) kgdb_error(KGDBERR_NOTHEXDIG); ch = hexValue << 4; if ((hexValue = hex(*buf++)) < 0) kgdb_error(KGDBERR_NOTHEXDIG); ch |= hexValue; *mem++ = ch; } kgdb_flush_cache_range((void *)mem_start, (void *)(mem - 1)); longjmp_on_fault = 0; return buf; }
/* * This function does all command processing for interfacing to gdb. */ static int handle_exception (struct pt_regs *regs) { int addr; int length; char *ptr; kgdb_data kd; int i; if (!initialized) { printf("kgdb: exception before kgdb is initialized! huh?\n"); return (0); } /* probably should check which exception occured as well */ if (longjmp_on_fault) { longjmp_on_fault = 0; kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT); panic("kgdb longjump failed!\n"); } if (kgdb_active) { printf("kgdb: unexpected exception from within kgdb\n"); return (0); } kgdb_active = 1; kgdb_interruptible(0); printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs)); if (kgdb_setjmp(error_jmp_buf) != 0) panic("kgdb: error or fault in entry init!\n"); kgdb_enter(regs, &kd); if (first_entry) { /* * the first time we enter kgdb, we save the processor * state so that we can return to the monitor if the * remote end quits gdb (or at least, tells us to quit * with the 'k' packet) */ entry_regs = *regs; first_entry = 0; } ptr = remcomOutBuffer; *ptr++ = 'T'; *ptr++ = hexchars[kd.sigval >> 4]; *ptr++ = hexchars[kd.sigval & 0xf]; for (i = 0; i < kd.nregs; i++) { kgdb_reg *rp = &kd.regs[i]; *ptr++ = hexchars[rp->num >> 4]; *ptr++ = hexchars[rp->num & 0xf]; *ptr++ = ':'; ptr = (char *)mem2hex((char *)&rp->val, ptr, 4); *ptr++ = ';'; } *ptr = 0; #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); #endif putpacket((unsigned char *)&remcomOutBuffer); while (1) { volatile int errnum; remcomOutBuffer[0] = 0; getpacket(remcomInBuffer); ptr = &remcomInBuffer[1]; #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer); #endif errnum = kgdb_setjmp(error_jmp_buf); if (errnum == 0) switch (remcomInBuffer[0]) { case '?': /* report most recent signal */ remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[kd.sigval >> 4]; remcomOutBuffer[2] = hexchars[kd.sigval & 0xf]; remcomOutBuffer[3] = 0; break; #ifdef KGDB_DEBUG case 'd': /* toggle debug flag */ kdebug ^= 1; break; #endif case 'g': /* return the value of the CPU registers. */ length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX); mem2hex(remcomRegBuffer, remcomOutBuffer, length); break; case 'G': /* set the value of the CPU registers */ length = strlen(ptr); if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS); hex2mem(ptr, remcomRegBuffer, length/2); kgdb_putregs(regs, remcomRegBuffer, length/2); strcpy(remcomOutBuffer,"OK"); break; case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ /* Try to read %x,%x. */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) { mem2hex((char *)addr, remcomOutBuffer, length); } else { kgdb_error(KGDBERR_BADPARAMS); } break; case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ /* Try to read '%x,%x:'. */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':') { hex2mem(ptr, (char *)addr, length); strcpy(remcomOutBuffer, "OK"); } else { kgdb_error(KGDBERR_BADPARAMS); } break; case 'k': /* kill the program, actually return to monitor */ kd.extype = KGDBEXIT_KILL; *regs = entry_regs; first_entry = 1; goto doexit; case 'C': /* CSS continue with signal SS */ *ptr = '\0'; /* ignore the signal number for now */ /* fall through */ case 'c': /* cAA..AA Continue; address AA..AA optional */ /* try to read optional parameter, pc unchanged if no parm */ kd.extype = KGDBEXIT_CONTINUE; if (hexToInt(&ptr, &addr)) { kd.exaddr = addr; kd.extype |= KGDBEXIT_WITHADDR; } goto doexit; case 'S': /* SSS single step with signal SS */ *ptr = '\0'; /* ignore the signal number for now */ /* fall through */ case 's': kd.extype = KGDBEXIT_SINGLE; if (hexToInt(&ptr, &addr)) { kd.exaddr = addr; kd.extype |= KGDBEXIT_WITHADDR; } doexit: /* Need to flush the instruction cache here, as we may have deposited a * breakpoint, and the icache probably has no way of knowing that a data ref to * some location may have changed something that is in the instruction cache. */ kgdb_flush_cache_all(); kgdb_exit(regs, &kd); kgdb_active = 0; kgdb_interruptible(1); return (1); case 'r': /* Reset (if user process..exit ???)*/ panic("kgdb reset."); break; case 'P': /* Pr=v set reg r to value v (r and v are hex) */ if (hexToInt(&ptr, &addr) && *ptr++ == '=' && ((length = strlen(ptr)) & 1) == 0) { hex2mem(ptr, remcomRegBuffer, length/2); kgdb_putreg(regs, addr, remcomRegBuffer, length/2); strcpy(remcomOutBuffer,"OK"); } else { kgdb_error(KGDBERR_BADPARAMS); } break; } /* switch */ if (errnum != 0) sprintf(remcomOutBuffer, "E%02d", errnum); #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); #endif /* reply to the request */ putpacket((unsigned char *)&remcomOutBuffer); } /* while(1) */ }
void kgdb_putregs(struct pt_regs *regs, char *buf, int length) { unsigned long *gdb_regs = (unsigned long *)buf; if (length != BFIN_NUM_REGS) kgdb_error(KGDBERR_NOSPACE); if ((unsigned long)gdb_regs & 3) kgdb_error(KGDBERR_ALIGNFAULT); regs->r0 = gdb_regs[BFIN_R0]; regs->r1 = gdb_regs[BFIN_R1]; regs->r2 = gdb_regs[BFIN_R2]; regs->r3 = gdb_regs[BFIN_R3]; regs->r4 = gdb_regs[BFIN_R4]; regs->r5 = gdb_regs[BFIN_R5]; regs->r6 = gdb_regs[BFIN_R6]; regs->r7 = gdb_regs[BFIN_R7]; regs->p0 = gdb_regs[BFIN_P0]; regs->p1 = gdb_regs[BFIN_P1]; regs->p2 = gdb_regs[BFIN_P2]; regs->p3 = gdb_regs[BFIN_P3]; regs->p4 = gdb_regs[BFIN_P4]; regs->p5 = gdb_regs[BFIN_P5]; regs->fp = gdb_regs[BFIN_FP]; /* regs->sp = gdb_regs[BFIN_ ]; */ regs->i0 = gdb_regs[BFIN_I0]; regs->i1 = gdb_regs[BFIN_I1]; regs->i2 = gdb_regs[BFIN_I2]; regs->i3 = gdb_regs[BFIN_I3]; regs->m0 = gdb_regs[BFIN_M0]; regs->m1 = gdb_regs[BFIN_M1]; regs->m2 = gdb_regs[BFIN_M2]; regs->m3 = gdb_regs[BFIN_M3]; regs->b0 = gdb_regs[BFIN_B0]; regs->b1 = gdb_regs[BFIN_B1]; regs->b2 = gdb_regs[BFIN_B2]; regs->b3 = gdb_regs[BFIN_B3]; regs->l0 = gdb_regs[BFIN_L0]; regs->l1 = gdb_regs[BFIN_L1]; regs->l2 = gdb_regs[BFIN_L2]; regs->l3 = gdb_regs[BFIN_L3]; regs->a0x = gdb_regs[BFIN_A0_DOT_X]; regs->a0w = gdb_regs[BFIN_A0_DOT_W]; regs->a1x = gdb_regs[BFIN_A1_DOT_X]; regs->a1w = gdb_regs[BFIN_A1_DOT_W]; regs->rets = gdb_regs[BFIN_RETS]; regs->lc0 = gdb_regs[BFIN_LC0]; regs->lt0 = gdb_regs[BFIN_LT0]; regs->lb0 = gdb_regs[BFIN_LB0]; regs->lc1 = gdb_regs[BFIN_LC1]; regs->lt1 = gdb_regs[BFIN_LT1]; regs->lb1 = gdb_regs[BFIN_LB1]; regs->usp = gdb_regs[BFIN_USP]; regs->syscfg = gdb_regs[BFIN_SYSCFG]; regs->retx = gdb_regs[BFIN_PC]; regs->retn = gdb_regs[BFIN_RETN]; regs->rete = gdb_regs[BFIN_RETE]; regs->pc = gdb_regs[BFIN_PC]; #if 0 /* can't change these */ regs->astat = gdb_regs[BFIN_ASTAT]; regs->seqstat = gdb_regs[BFIN_SEQSTAT]; regs->ipend = gdb_regs[BFIN_IPEND]; #endif }
/* * putreg - put kgdb's reg (regno) into the pt_regs */ void kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length) { unsigned long *ptr = (unsigned long *)buf; if (regno < 0 || regno > BFIN_NUM_REGS) kgdb_error(KGDBERR_BADPARAMS); if (length < 4) kgdb_error(KGDBERR_NOSPACE); if ((unsigned long)ptr & 3) kgdb_error(KGDBERR_ALIGNFAULT); switch (regno) { case BFIN_R0: regs->r0 = *ptr; break; case BFIN_R1: regs->r1 = *ptr; break; case BFIN_R2: regs->r2 = *ptr; break; case BFIN_R3: regs->r3 = *ptr; break; case BFIN_R4: regs->r4 = *ptr; break; case BFIN_R5: regs->r5 = *ptr; break; case BFIN_R6: regs->r6 = *ptr; break; case BFIN_R7: regs->r7 = *ptr; break; case BFIN_P0: regs->p0 = *ptr; break; case BFIN_P1: regs->p1 = *ptr; break; case BFIN_P2: regs->p2 = *ptr; break; case BFIN_P3: regs->p3 = *ptr; break; case BFIN_P4: regs->p4 = *ptr; break; case BFIN_P5: regs->p5 = *ptr; break; case BFIN_SP: regs->reserved = *ptr; break; case BFIN_FP: regs->fp = *ptr; break; case BFIN_I0: regs->i0 = *ptr; break; case BFIN_I1: regs->i1 = *ptr; break; case BFIN_I2: regs->i2 = *ptr; break; case BFIN_I3: regs->i3 = *ptr; break; case BFIN_M0: regs->m0 = *ptr; break; case BFIN_M1: regs->m1 = *ptr; break; case BFIN_M2: regs->m2 = *ptr; break; case BFIN_M3: regs->m3 = *ptr; break; case BFIN_B0: regs->b0 = *ptr; break; case BFIN_B1: regs->b1 = *ptr; break; case BFIN_B2: regs->b2 = *ptr; break; case BFIN_B3: regs->b3 = *ptr; break; case BFIN_L0: regs->l0 = *ptr; break; case BFIN_L1: regs->l1 = *ptr; break; case BFIN_L2: regs->l2 = *ptr; break; case BFIN_L3: regs->l3 = *ptr; break; case BFIN_A0_DOT_X: regs->a0x = *ptr; break; case BFIN_A0_DOT_W: regs->a0w = *ptr; break; case BFIN_A1_DOT_X: regs->a1x = *ptr; break; case BFIN_A1_DOT_W: regs->a1w = *ptr; break; case BFIN_ASTAT: regs->astat = *ptr; break; case BFIN_RETS: regs->rets = *ptr; break; case BFIN_LC0: regs->lc0 = *ptr; break; case BFIN_LT0: regs->lt0 = *ptr; break; case BFIN_LB0: regs->lb0 = *ptr; break; case BFIN_LC1: regs->lc1 = *ptr; break; case BFIN_LT1: regs->lt1 = *ptr; break; case BFIN_LB1: regs->lb1 = *ptr; break; /* BFIN_CYCLES, BFIN_CYCLES2, BFIN_USP, BFIN_SEQSTAT, BFIN_SYSCFG, */ case BFIN_RETX: regs->retx = *ptr; break; case BFIN_RETN: regs->retn = *ptr; break; case BFIN_RETE: regs->rete = *ptr; break; case BFIN_PC: regs->pc = *ptr; break; default: kgdb_error(KGDBERR_BADPARAMS); } }
/* * getregs - gets the pt_regs, and gives them to kgdb's buffer */ int kgdb_getregs(struct pt_regs *regs, char *buf, int max) { unsigned long *gdb_regs = (unsigned long *)buf; if (max < NUMREGBYTES) kgdb_error(KGDBERR_NOSPACE); if ((unsigned long)gdb_regs & 3) kgdb_error(KGDBERR_ALIGNFAULT); gdb_regs[BFIN_R0] = regs->r0; gdb_regs[BFIN_R1] = regs->r1; gdb_regs[BFIN_R2] = regs->r2; gdb_regs[BFIN_R3] = regs->r3; gdb_regs[BFIN_R4] = regs->r4; gdb_regs[BFIN_R5] = regs->r5; gdb_regs[BFIN_R6] = regs->r6; gdb_regs[BFIN_R7] = regs->r7; gdb_regs[BFIN_P0] = regs->p0; gdb_regs[BFIN_P1] = regs->p1; gdb_regs[BFIN_P2] = regs->p2; gdb_regs[BFIN_P3] = regs->p3; gdb_regs[BFIN_P4] = regs->p4; gdb_regs[BFIN_P5] = regs->p5; gdb_regs[BFIN_SP] = (unsigned long)regs; gdb_regs[BFIN_FP] = regs->fp; gdb_regs[BFIN_I0] = regs->i0; gdb_regs[BFIN_I1] = regs->i1; gdb_regs[BFIN_I2] = regs->i2; gdb_regs[BFIN_I3] = regs->i3; gdb_regs[BFIN_M0] = regs->m0; gdb_regs[BFIN_M1] = regs->m1; gdb_regs[BFIN_M2] = regs->m2; gdb_regs[BFIN_M3] = regs->m3; gdb_regs[BFIN_B0] = regs->b0; gdb_regs[BFIN_B1] = regs->b1; gdb_regs[BFIN_B2] = regs->b2; gdb_regs[BFIN_B3] = regs->b3; gdb_regs[BFIN_L0] = regs->l0; gdb_regs[BFIN_L1] = regs->l1; gdb_regs[BFIN_L2] = regs->l2; gdb_regs[BFIN_L3] = regs->l3; gdb_regs[BFIN_A0_DOT_X] = regs->a0x; gdb_regs[BFIN_A0_DOT_W] = regs->a0w; gdb_regs[BFIN_A1_DOT_X] = regs->a1x; gdb_regs[BFIN_A1_DOT_W] = regs->a1w; gdb_regs[BFIN_ASTAT] = regs->astat; gdb_regs[BFIN_RETS] = regs->rets; gdb_regs[BFIN_LC0] = regs->lc0; gdb_regs[BFIN_LT0] = regs->lt0; gdb_regs[BFIN_LB0] = regs->lb0; gdb_regs[BFIN_LC1] = regs->lc1; gdb_regs[BFIN_LT1] = regs->lt1; gdb_regs[BFIN_LB1] = regs->lb1; gdb_regs[BFIN_CYCLES] = 0; gdb_regs[BFIN_CYCLES2] = 0; gdb_regs[BFIN_USP] = regs->usp; gdb_regs[BFIN_SEQSTAT] = regs->seqstat; gdb_regs[BFIN_SYSCFG] = regs->syscfg; gdb_regs[BFIN_RETI] = regs->pc; gdb_regs[BFIN_RETX] = regs->retx; gdb_regs[BFIN_RETN] = regs->retn; gdb_regs[BFIN_RETE] = regs->rete; gdb_regs[BFIN_PC] = regs->pc; gdb_regs[BFIN_CC] = 0; gdb_regs[BFIN_EXTRA1] = 0; gdb_regs[BFIN_EXTRA2] = 0; gdb_regs[BFIN_EXTRA3] = 0; gdb_regs[BFIN_IPEND] = regs->ipend; return NUMREGBYTES; }