📄 kgdb.c
字号:
/* 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 breakpoint. */ /* Bit 0 in BP_CTRL holds the configuration for I0. */ if (!(sreg.s0_3 & 0x1)) { /* Not in use. */ gdb_cris_strcpy(output_buffer, error_message[E04]); return; } /* Deconfigure. */ sreg.s1_3 = 0; sreg.s2_3 = 0; sreg.s0_3 &= ~1; } else { int bp; unsigned int *bp_d_regs = &sreg.s3_3; /* Try to find a watchpoint that is configured for the specified range, then check that read/write also matches. */ /* Ugly pointer arithmetic, since I cannot rely on a single switch (addr) as there may be several watchpoints with the same start address for example. */ for (bp = 0; bp < 6; bp++) { if (bp_d_regs[bp * 2] == addr && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) { /* Matching range. */ int bitpos = 2 + bp * 4; int rw_bits; /* Read/write bits for this BP. */ rw_bits = (sreg.s0_3 & (0x3 << bitpos)) >> bitpos; if ((type == '3' && rw_bits == 0x1) || (type == '2' && rw_bits == 0x2) || (type == '4' && rw_bits == 0x3)) { /* Read/write matched. */ break; } } } if (bp > 5) { /* No watchpoint matched. */ gdb_cris_strcpy(output_buffer, error_message[E04]); return; } /* Found a matching watchpoint. Now, deconfigure it by both disabling read/write in bp_ctrl and zeroing its start/end addresses. */ sreg.s0_3 &= ~(3 << (2 + (bp * 4))); bp_d_regs[bp * 2] = 0; bp_d_regs[bp * 2 + 1] = 0; } /* Note that we don't clear the S1 flag here. It's done when continuing. */ gdb_cris_strcpy(output_buffer, "OK");}/* All expected commands are sent from remote.c. Send a response according to the description in remote.c. */voidhandle_exception(int sigval){ /* Avoid warning of not used. */ USEDFUN(handle_exception); USEDVAR(internal_stack[0]); register_fixup(sigval); /* Send response. */ stub_is_stopped(sigval); for (;;) { output_buffer[0] = '\0'; getpacket(input_buffer); switch (input_buffer[0]) { case 'g': /* Read registers: g Success: Each byte of register data is described by two hex digits. Registers are in the internal order for GDB, and the bytes in a register are in the same order the machine uses. Failure: void. */ { char *buf; /* General and special registers. */ buf = mem2hex(output_buffer, (char *)®, sizeof(registers)); /* Support registers. */ /* -1 because of the null termination that mem2hex adds. */ mem2hex(buf, (char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), 16 * sizeof(unsigned int)); break; } case 'G': /* Write registers. GXX..XX Each byte of register data is described by two hex digits. Success: OK Failure: void. */ /* General and special registers. */ hex2mem((char *)®, &input_buffer[1], sizeof(registers)); /* Support registers. */ hex2mem((char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), &input_buffer[1] + sizeof(registers), 16 * sizeof(unsigned int)); gdb_cris_strcpy(output_buffer, "OK"); break; case 'P': /* Write register. Pn...=r... Write register n..., hex value without 0x, with value r..., which contains a hex value without 0x and two hex digits for each byte in the register (target byte order). P1f=11223344 means set register 31 to 44332211. Success: OK Failure: E02, E05 */ { char *suffix; int regno = gdb_cris_strtol(&input_buffer[1], &suffix, 16); int status; status = write_register(regno, suffix+1); switch (status) { case E02: /* Do not support read-only registers. */ gdb_cris_strcpy(output_buffer, error_message[E02]); break; case E05: /* Do not support non-existing registers. */ gdb_cris_strcpy(output_buffer, error_message[E05]); break; default: /* Valid register number. */ gdb_cris_strcpy(output_buffer, "OK"); break; } } break; case 'm': /* Read from memory. mAA..AA,LLLL AA..AA is the address and LLLL is the length. Success: XX..XX is the memory content. Can be fewer bytes than requested if only part of the data may be read. m6000120a,6c means retrieve 108 byte from base address 6000120a. Failure: void. */ { char *suffix; unsigned char *addr = (unsigned char *)gdb_cris_strtol(&input_buffer[1], &suffix, 16); int len = gdb_cris_strtol(suffix+1, 0, 16); /* Bogus read (i.e. outside the kernel's segment)? . */ if (!((unsigned int)addr >= 0xc0000000 && (unsigned int)addr < 0xd0000000)) addr = NULL; mem2hex(output_buffer, addr, len); } break; case 'X': /* Write to memory. XAA..AA,LLLL:XX..XX AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the binary data. Success: OK Failure: void. */ case 'M': /* Write to memory. MAA..AA,LLLL:XX..XX AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the hexadecimal data. Success: OK Failure: void. */ { char *lenptr; char *dataptr; unsigned char *addr = (unsigned char *)gdb_cris_strtol(&input_buffer[1], &lenptr, 16); int len = gdb_cris_strtol(lenptr+1, &dataptr, 16); if (*lenptr == ',' && *dataptr == ':') { if (input_buffer[0] == 'M') { hex2mem(addr, dataptr + 1, len); } else /* X */ { bin2mem(addr, dataptr + 1, len); } gdb_cris_strcpy(output_buffer, "OK"); } else { gdb_cris_strcpy(output_buffer, error_message[E06]); } } break; case 'c': /* Continue execution. cAA..AA AA..AA is the address where execution is resumed. If AA..AA is omitted, resume at the present address. Success: return to the executing thread. Failure: will never know. */ if (input_buffer[1] != '\0') { /* FIXME: Doesn't handle address argument. */ gdb_cris_strcpy(output_buffer, error_message[E04]); break; } /* Before continuing, make sure everything is set up correctly. */ /* Set the SPC to some unlikely value. */ reg.spc = 0; /* Set the S1 flag to 0 unless some watchpoint is enabled (since setting S1 to 0 would also disable watchpoints). (Note that bits 26-31 in BP_CTRL are reserved, so don't check against those). */ if ((sreg.s0_3 & 0x3fff) == 0) { reg.ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT)); } return; case 's': /* Step. sAA..AA AA..AA is the address where execution is resumed. If AA..AA is omitted, resume at the present address. Success: return to the executing thread. Failure: will never know. */ if (input_buffer[1] != '\0') { /* FIXME: Doesn't handle address argument. */ gdb_cris_strcpy(output_buffer, error_message[E04]); break; } /* Set the SPC to PC, which is where we'll return (deduced previously). */ reg.spc = reg.pc; /* Set the S1 (first stacked, not current) flag, which will kick into action when we rfe. */ reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); return; case 'Z': /* Insert breakpoint or watchpoint, Ztype,addr,length. Remote protocol says: A remote target shall return an empty string for an unrecognized breakpoint or watchpoint packet type. */ { char *lenptr; char *dataptr; int addr = gdb_cris_strtol(&input_buffer[3], &lenptr, 16); int len = gdb_cris_strtol(lenptr + 1, &dataptr, 16); char type = input_buffer[1]; insert_watchpoint(type, addr, len); break; } case 'z': /* Remove breakpoint or watchpoint, Ztype,addr,length. Remote protocol says: A remote target shall return an empty string for an unrecognized breakpoint or watchpoint packet type. */ { char *lenptr; char *dataptr; int addr = gdb_cris_strtol(&input_buffer[3], &lenptr, 16); int len = gdb_cris_strtol(lenptr + 1, &dataptr, 16); char type = input_buffer[1]; remove_watchpoint(type, addr, len); break; } case '?': /* The last signal which caused a stop. ? Success: SAA, where AA is the signal number. Failure: void. */ output_buffer[0] = 'S'; output_buffer[1] = highhex(sigval); output_buffer[2] = lowhex(sigval); output_buffer[3] = 0; break; case 'D': /* Detach from host. D Success: OK, and return to the executing thread. Failure: will never know */ putpacket("OK"); return; case 'k': case 'r': /* kill request or reset request. Success: restart of target. Failure: will never know. */ kill_restart(); break; case 'C': case 'S': case '!': case 'R': case 'd': /* Continue with signal sig. Csig;AA..AA Step with signal sig. Ssig;AA..AA Use the extended remote protocol. ! Restart the target system. R0 Toggle debug flag. d Search backwards. tAA:PP,MM Not supported: E04 */ /* FIXME: What's the difference between not supported and ignored (below)? */ gdb_cris_strcpy(output_buffer, error_message[E04]); break; default: /* The stub should ignore other request and send an empty response ($#<checksum>). This way we can extend the protocol and GDB can tell whether the stub it is talking to uses the old or the new. */ output_buffer[0] = 0; break; } putpacket(output_buffer); }}voidkgdb_init(void){ reg_intr_vect_rw_mask intr_mask; reg_ser_rw_intr_mask ser_intr_mask; /* Configure the kgdb serial port. */#if defined(CONFIG_ETRAX_KGDB_PORT0) /* Note: no shortcut registered (not handled by multiple_interrupt). See entry.S. */ set_exception_vector(SER0_INTR_VECT, kgdb_handle_exception); /* Enable the ser irq in the global config. */ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); intr_mask.ser0 = 1; REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask); ser_intr_mask.data_avail = regk_ser_yes; REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask);#elif defined(CONFIG_ETRAX_KGDB_PORT1) /* Note: no shortcut registered (not handled by multiple_interrupt). See entry.S. */ set_exception_vector(SER1_INTR_VECT, kgdb_handle_exception); /* Enable the ser irq in the global config. */ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); intr_mask.ser1 = 1; REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask); ser_intr_mask.data_avail = regk_ser_yes; REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask);#elif defined(CONFIG_ETRAX_KGDB_PORT2) /* Note: no shortcut registered (not handled by multiple_interrupt). See entry.S. */ set_exception_vector(SER2_INTR_VECT, kgdb_handle_exception); /* Enable the ser irq in the global config. */ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); intr_mask.ser2 = 1; REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask); ser_intr_mask.data_avail = regk_ser_yes; REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask);#elif defined(CONFIG_ETRAX_KGDB_PORT3) /* Note: no shortcut registered (not handled by multiple_interrupt). See entry.S. */ set_exception_vector(SER3_INTR_VECT, kgdb_handle_exception); /* Enable the ser irq in the global config. */ intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); intr_mask.ser3 = 1; REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask); ser_intr_mask.data_avail = regk_ser_yes; REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask);#endif}/* Performs a complete re-start from scratch. */static voidkill_restart(void){ machine_restart("");}/* Use this static breakpoint in the start-up only. */voidbreakpoint(void){ kgdb_started = 1; dynamic_bp = 0; /* This is a static, not a dynamic breakpoint. */ __asm__ volatile ("break 8"); /* Jump to kgdb_handle_breakpoint. */}/****************************** End of file **********************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -