📄 kgdb.c
字号:
static voidputpacket(char *buffer){ int checksum; int runlen; int encode; do { char *src = buffer; putDebugChar('$'); checksum = 0; while (*src) { /* Do run length encoding */ putDebugChar(*src); checksum += *src; runlen = 0; while (runlen < RUNLENMAX && *src == src[runlen]) { runlen++; } if (runlen > 3) { /* Got a useful amount */ putDebugChar ('*'); checksum += '*'; encode = runlen + ' ' - 4; putDebugChar(encode); checksum += encode; src += runlen; } else { src++; } } putDebugChar('#'); putDebugChar(highhex (checksum)); putDebugChar(lowhex (checksum)); } while(kgdb_started && (getDebugChar() != '+'));}/* The string str is prepended with the GDB printout token and sent. Required in traditional implementations. */voidputDebugString(const unsigned char *str, int len){ /* Move SPC forward if we are single-stepping. */ asm("spchere:"); asm("move $spc, $r10"); asm("cmp.d spchere, $r10"); asm("bne nosstep"); asm("nop"); asm("move.d spccont, $r10"); asm("move $r10, $spc"); asm("nosstep:"); output_buffer[0] = 'O'; mem2hex(&output_buffer[1], (unsigned char *)str, len); putpacket(output_buffer); asm("spccont:");}/********************************** Handle exceptions ************************//* Build and send a response packet in order to inform the host the stub is stopped. TAAn...:r...;n...:r...;n...:r...; AA = signal number n... = register number (hex) r... = register contents n... = `thread' r... = thread process ID. This is a hex integer. n... = other string not starting with valid hex digit. gdb should ignore this n,r pair and go on to the next. This way we can extend the protocol. */static voidstub_is_stopped(int sigval){ char *ptr = output_buffer; unsigned int reg_cont; /* Send trap type (converted to signal) */ *ptr++ = 'T'; *ptr++ = highhex(sigval); *ptr++ = lowhex(sigval); if (((reg.exs & 0xff00) >> 8) == 0xc) { /* Some kind of hardware watchpoint triggered. Find which one and determine its type (read/write/access). */ int S, bp, trig_bits = 0, rw_bits = 0; int trig_mask = 0; unsigned int *bp_d_regs = &sreg.s3_3; /* In a lot of cases, the stopped data address will simply be EDA. In some cases, we adjust it to match the watched data range. (We don't want to change the actual EDA though). */ unsigned int stopped_data_address; /* The S field of EXS. */ S = (reg.exs & 0xffff0000) >> 16; if (S & 1) { /* Instruction watchpoint. */ /* FIXME: Check against, and possibly adjust reported EDA. */ } else { /* Data watchpoint. Find the one that triggered. */ for (bp = 0; bp < 6; bp++) { /* Dx_RD, Dx_WR in the S field of EXS for this BP. */ int bitpos_trig = 1 + bp * 2; /* Dx_BPRD, Dx_BPWR in BP_CTRL for this BP. */ int bitpos_config = 2 + bp * 4; /* Get read/write trig bits for this BP. */ trig_bits = (S & (3 << bitpos_trig)) >> bitpos_trig; /* Read/write config bits for this BP. */ rw_bits = (sreg.s0_3 & (3 << bitpos_config)) >> bitpos_config; if (trig_bits) { /* Sanity check: the BP shouldn't trigger for accesses that it isn't configured for. */ if ((rw_bits == 0x1 && trig_bits != 0x1) || (rw_bits == 0x2 && trig_bits != 0x2)) panic("Invalid r/w trigging for this BP"); /* Mark this BP as trigged for future reference. */ trig_mask |= (1 << bp); if (reg.eda >= bp_d_regs[bp * 2] && reg.eda <= bp_d_regs[bp * 2 + 1]) { /* EDA withing range for this BP; it must be the one we're looking for. */ stopped_data_address = reg.eda; break; } } } if (bp < 6) { /* Found a trigged BP with EDA within its configured data range. */ } else if (trig_mask) { /* Something triggered, but EDA doesn't match any BP's range. */ for (bp = 0; bp < 6; bp++) { /* Dx_BPRD, Dx_BPWR in BP_CTRL for this BP. */ int bitpos_config = 2 + bp * 4; /* Read/write config bits for this BP (needed later). */ rw_bits = (sreg.s0_3 & (3 << bitpos_config)) >> bitpos_config; if (trig_mask & (1 << bp)) { /* EDA within 31 bytes of the configured start address? */ if (reg.eda + 31 >= bp_d_regs[bp * 2]) { /* Changing the reported address to match the start address of the first applicable BP. */ stopped_data_address = bp_d_regs[bp * 2]; break; } else { /* We continue since we might find another useful BP. */ printk("EDA doesn't match trigged BP's range"); } } } } /* No match yet? */ BUG_ON(bp >= 6); /* Note that we report the type according to what the BP is configured for (otherwise we'd never report an 'awatch'), not according to how it trigged. We did check that the trigged bits match what the BP is configured for though. */ if (rw_bits == 0x1) { /* read */ strncpy(ptr, "rwatch", 6); ptr += 6; } else if (rw_bits == 0x2) { /* write */ strncpy(ptr, "watch", 5); ptr += 5; } else if (rw_bits == 0x3) { /* access */ strncpy(ptr, "awatch", 6); ptr += 6; } else { panic("Invalid r/w bits for this BP."); } *ptr++ = ':'; /* Note that we don't read_register(EDA, ...) */ ptr = mem2hex_nbo(ptr, (unsigned char *)&stopped_data_address, register_size[EDA]); *ptr++ = ';'; } } /* Only send PC, frame and stack pointer. */ read_register(PC, ®_cont); *ptr++ = highhex(PC); *ptr++ = lowhex(PC); *ptr++ = ':'; ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[PC]); *ptr++ = ';'; read_register(R8, ®_cont); *ptr++ = highhex(R8); *ptr++ = lowhex(R8); *ptr++ = ':'; ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[R8]); *ptr++ = ';'; read_register(SP, ®_cont); *ptr++ = highhex(SP); *ptr++ = lowhex(SP); *ptr++ = ':'; ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[SP]); *ptr++ = ';'; /* Send ERP as well; this will save us an entire register fetch in some cases. */ read_register(ERP, ®_cont); *ptr++ = highhex(ERP); *ptr++ = lowhex(ERP); *ptr++ = ':'; ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[ERP]); *ptr++ = ';'; /* null-terminate and send it off */ *ptr = 0; putpacket(output_buffer);}/* Returns the size of an instruction that has a delay slot. */int insn_size(unsigned long pc){ unsigned short opcode = *(unsigned short *)pc; int size = 0; switch ((opcode & 0x0f00) >> 8) { case 0x0: case 0x9: case 0xb: size = 2; break; case 0xe: case 0xf: size = 6; break; case 0xd: /* Could be 4 or 6; check more bits. */ if ((opcode & 0xff) == 0xff) size = 4; else size = 6; break; default: panic("Couldn't find size of opcode 0x%x at 0x%lx\n", opcode, pc); } return size;}void register_fixup(int sigval){ /* Compensate for ACR push at the beginning of exception handler. */ reg.sp += 4; /* Standard case. */ reg.pc = reg.erp; if (reg.erp & 0x1) { /* Delay slot bit set. Report as stopped on proper instruction. */ if (reg.spc) { /* Rely on SPC if set. */ reg.pc = reg.spc; } else { /* Calculate the PC from the size of the instruction that the delay slot we're in belongs to. */ reg.pc += insn_size(reg.erp & ~1) - 1 ; } } if ((reg.exs & 0x3) == 0x0) { /* Bits 1 - 0 indicate the type of memory operation performed by the interrupted instruction. 0 means no memory operation, and EDA is undefined in that case. We zero it to avoid confusion. */ reg.eda = 0; } if (sigval == SIGTRAP) { /* Break 8, single step or hardware breakpoint exception. */ /* Check IDX field of EXS. */ if (((reg.exs & 0xff00) >> 8) == 0x18) { /* Break 8. */ /* Static (compiled) breakpoints must return to the next instruction in order to avoid infinite loops (default value of ERP). Dynamic (gdb-invoked) must subtract the size of the break instruction from the ERP so that the instruction that was originally in the break instruction's place will be run when we return from the exception. */ if (!dynamic_bp) { /* Assuming that all breakpoints are dynamic from now on. */ dynamic_bp = 1; } else { /* Only if not in a delay slot. */ if (!(reg.erp & 0x1)) { reg.erp -= 2; reg.pc -= 2; } } } else if (((reg.exs & 0xff00) >> 8) == 0x3) { /* Single step. */ /* Don't fiddle with S1. */ } else if (((reg.exs & 0xff00) >> 8) == 0xc) { /* Hardware watchpoint exception. */ /* SPC has been updated so that we will get a single step exception when we return, but we don't want that. */ reg.spc = 0; /* Don't fiddle with S1. */ } } else if (sigval == SIGINT) { /* Nothing special. */ }}static void insert_watchpoint(char type, int addr, int len){ /* Breakpoint/watchpoint types (GDB terminology): 0 = memory breakpoint for instructions (not supported; done via memory write instead) 1 = hardware breakpoint for instructions (supported) 2 = write watchpoint (supported) 3 = read watchpoint (supported) 4 = access watchpoint (supported) */ if (type < '1' || type > '4') { output_buffer[0] = 0; return; } /* Read watchpoints are set as access watchpoints, because of GDB's inability to deal with pure read watchpoints. */ if (type == '3') type = '4'; if (type == '1') { /* Hardware (instruction) breakpoint. */ /* Bit 0 in BP_CTRL holds the configuration for I0. */ if (sreg.s0_3 & 0x1) { /* Already in use. */ gdb_cris_strcpy(output_buffer, error_message[E04]); return; } /* Configure. */ sreg.s1_3 = addr; sreg.s2_3 = (addr + len - 1); sreg.s0_3 |= 1; } else { int bp; unsigned int *bp_d_regs = &sreg.s3_3; /* The watchpoint allocation scheme is the simplest possible. For example, if a region is watched for read and a write watch is requested, a new watchpoint will be used. Also, if a watch for a region that is already covered by one or more existing watchpoints, a new watchpoint will be used. */ /* First, find a free data watchpoint. */ for (bp = 0; bp < 6; bp++) { /* Each data watchpoint's control registers occupy 2 bits (hence the 3), starting at bit 2 for D0 (hence the 2) with 4 bits between for each watchpoint (yes, the 4). */ if (!(sreg.s0_3 & (0x3 << (2 + (bp * 4))))) { break; } } if (bp > 5) { /* We're out of watchpoints. */ gdb_cris_strcpy(output_buffer, error_message[E04]); return; } /* Configure the control register first. */ if (type == '3' || type == '4') { /* Trigger on read. */ sreg.s0_3 |= (1 << (2 + bp * 4)); } if (type == '2' || type == '4') { /* Trigger on write. */ sreg.s0_3 |= (2 << (2 + bp * 4)); } /* Ugly pointer arithmetics to configure the watched range. */ bp_d_regs[bp * 2] = addr; bp_d_regs[bp * 2 + 1] = (addr + len - 1); } /* Set the S1 flag to enable watchpoints. */ reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); gdb_cris_strcpy(output_buffer, "OK");}static void remove_watchpoint(char type, int addr, int len){ /* Breakpoint/watchpoint types: 0 = memory breakpoint for instructions (not supported; done via memory write instead) 1 = hardware breakpoint for instructions (supported) 2 = write watchpoint (supported) 3 = read watchpoint (supported) 4 = access watchpoint (supported) */ if (type < '1' || type > '4') { output_buffer[0] = 0; return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -