123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005 |
- /*
- * GDB stub.
- *
- * Migarte form linux to rt-thread by Wzyy2
- * Original edition : KGDB stub
- *
- * File : gdb_stub.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006, RT-Thread Develop Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2014-07-04 Wzyy2 first version
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *
- * KGDB stub.
- *
- * Maintainer: Jason Wessel <jason.wessel@windriver.com>
- *
- * Copyright (C) 2000-2001 VERITAS Software Corporation.
- * Copyright (C) 2002-2004 Timesys Corporation
- * Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com>
- * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
- * Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org>
- * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd.
- * Copyright (C) 2005-2008 Wind River Systems, Inc.
- * Copyright (C) 2007 MontaVista Software, Inc.
- * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- *
- * Contributors at various stages not listed above:
- * Jason Wessel ( jason.wessel@windriver.com )
- * George Anzinger <george@mvista.com>
- * Anurekh Saxena (anurekh.saxena@timesys.com)
- * Lake Stevens Instrument Division (Glenn Engel)
- * Jim Kingdon, Cygnus Support.
- *
- * Original KGDB stub: David Grothe <dave@gcom.com>,
- * Tigran Aivazian <tigran@sco.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
- #include <rtthread.h>
- #include <rthw.h>
- #include <string.h>
- #include "gdb_stub.h"
- struct gdb_state {
- int signo;
- int pass_exception;
- }gs;
- /**
- * gdb_connected - Is a host GDB connected to us?
- */
- int gdb_connected;
- /*
- * Holds information about breakpoints in a kernel. These breakpoints are
- * added and removed by gdb.
- */
- #if RT_GDB_HAVE_SWBP
- static struct gdb_bkpt gdb_break[GDB_MAX_BREAKPOINTS] = {
- [0 ... GDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED }
- };
- #endif
- /* Storage for the registers, in GDB format. */
- static unsigned long gdb_regs[(NUMREGBYTES +
- sizeof(unsigned long) - 1) /
- sizeof(unsigned long)];
- char remcom_in_buffer[BUFMAX];
- char remcom_out_buffer[BUFMAX];
- static const char hexchars[] = "0123456789abcdef";
- //to call that there has been an error
- void* volatile gdb_mem_fault_handler = (void *)0;
- static long probe_kernel_write(void *dst, void *src, size_t size)
- {
- int i = 0;
- char *dst_ptr = (char *)dst;
- char *src_ptr = (char *)src;
- gdb_mem_fault_handler = &&err;
- for (i = 0; i<size; i++) {
- *(dst_ptr++) = *(src_ptr++);
- }
- gdb_mem_fault_handler = (void *)0;
- return 0;
- err:
- gdb_mem_fault_handler = (void *)0;
- return -1;
- }
- /*
- * GDB remote protocol parser:
- */
- static int hex(char ch)
- {
- if ((ch >= 'a') && (ch <= 'f'))
- return ch - 'a' + 10;
- if ((ch >= '0') && (ch <= '9'))
- return ch - '0';
- if ((ch >= 'A') && (ch <= 'F'))
- return ch - 'A' + 10;
- return -1;
- }
- static char tohex(char c)
- {
- return hexchars[c & 15];
- }
- /*
- * Copy the binary array pointed to by buf into mem. Fix $, #, and
- * 0x7d escaped with 0x7d. Return a pointer to the character after
- * the last byte written.
- */
- int gdb_ebin2mem(char *buf, char *mem, int count)
- {
- int err = 0;
- char c;
- while (count-- > 0) {
- c = *buf++;
- if (c == 0x7d)
- c = *buf++ ^ 0x20;
- err = probe_kernel_write(mem, &c, 1);
- if (err)
- break;
- mem++;
- }
- return err;
- }
- /*
- * 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 written.
- * May return an error.
- */
- int gdb_hex2mem(char *buf, char *mem, int count)
- {
- char *tmp_raw;
- char *tmp_hex;
- tmp_raw = buf + count * 2;
- tmp_hex = tmp_raw - 1;
- while (tmp_hex >= buf) {
- tmp_raw--;
- *tmp_raw = hex(*tmp_hex--);
- *tmp_raw |= hex(*tmp_hex--) << 4;
- }
- return probe_kernel_write(mem, tmp_raw, count);
- }
- /*
- * Convert the memory pointed to by mem into hex, placing result in buf.
- * Return a pointer to the last char put in buf (null). May return an error.
- */
- int gdb_mem2hex(char *mem, char *buf, int count)
- {
- char *tmp = mem;
- char ch;
- gdb_mem_fault_handler = &&err;
- while (count > 0) {
- ch = *(tmp++);
- *(buf++) = tohex((ch >> 4) & 0xf);
- *(buf++) = tohex(ch & 0xf);
- count--;
- }
- *buf = 0;
- gdb_mem_fault_handler = (void *)0;
- return 0;
- err:
- gdb_mem_fault_handler = (void *)0;
- return -1;
- }
- /*
- * While we find nice hex chars, build a long_val.
- * Return number of chars processed.
- */
- int gdb_hex2long(char **ptr, unsigned long *long_val)
- {
- int hex_val;
- int num = 0;
- int negate = 0;
- *long_val = 0;
- if (**ptr == '-') {
- negate = 1;
- (*ptr)++;
- }
- while (**ptr) {
- hex_val = hex(**ptr);
- if (hex_val < 0)
- break;
- *long_val = (*long_val << 4) | hex_val;
- num++;
- (*ptr)++;
- }
- if (negate)
- *long_val = -*long_val;
- return num;
- }
- /* Write memory due to an 'M' or 'X' packet. */
- static int write_mem_msg(int binary)
- {
- char *ptr = &remcom_in_buffer[1];
- unsigned long addr;
- unsigned long length;
- int err;
- if (gdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' &&
- gdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') {
- #ifdef GDB_DATA_ACCESS
- //accesses to areas not backed can cause error
- if (gdb_permit_data_access(addr, length))
- return -1;
- #endif
- if (binary)
- err = gdb_ebin2mem(ptr, (char *)addr, length);
- else
- err = gdb_hex2mem(ptr, (char *)addr, length);
- if (err)
- return err;
- #ifdef RT_GDB_ICACHE
- if (CACHE_FLUSH_IS_SAFE)
- gdb_flush_icache_range(addr, addr + length);
- #endif
- return 0;
- }
- return -1;
- }
- /*
- * Send the packet in buffer.
- * Check for gdb connection if asked for.
- */
- static void put_packet(char *buffer)
- {
- unsigned char checksum;
- int count;
- char ch;
- /*
- * $<packet info>#<checksum>.
- */
- while (1) {
- gdb_io_ops.write_char('$');
- checksum = 0;
- count = 0;
- while ((ch = buffer[count])) {
- gdb_io_ops.write_char(ch);
- checksum += ch;
- count++;
- }
- gdb_io_ops.write_char('#');
- gdb_io_ops.write_char(tohex((checksum >> 4) & 0xf));
- gdb_io_ops.write_char(tohex(checksum & 0xf));
- /* Now see what we get in reply. */
- ch = gdb_io_ops.read_char();
- /* If we get an ACK, we are done. */
- if (ch == '+')
- return;
- /*
- * If we get the start of another packet, this means
- * that GDB is attempting to reconnect. We will NAK
- * the packet being sent, and stop trying to send this
- * packet.
- */
- if (ch == '$') {
- gdb_io_ops.write_char('-');
- if (gdb_io_ops.flush)
- gdb_io_ops.flush();
- return;
- }
- }
- }
- /* scan for the sequence $<data>#<checksum> */
- static void get_packet(char *buffer)
- {
- unsigned char checksum;
- unsigned char xmitcsum;
- int count;
- char ch;
- do {
- /*
- * Spin and wait around for the start character, ignore all
- * other characters:
- */
- while ((ch = (gdb_io_ops.read_char())) != '$')
- /* nothing */;
- gdb_connected = 1;
- checksum = 0;
- xmitcsum = -1;
- count = 0;
- /*
- * now, read until a # or end of buffer is found:
- */
- while (count < (BUFMAX - 1)) {
- ch = gdb_io_ops.read_char();
- if (ch == '#')
- break;
- checksum = checksum + ch;
- buffer[count] = ch;
- count = count + 1;
- }
- buffer[count] = 0;
- if (ch == '#') {
- xmitcsum = hex(gdb_io_ops.read_char()) << 4;
- xmitcsum += hex(gdb_io_ops.read_char());
- if (checksum != xmitcsum)
- /* failed checksum */
- gdb_io_ops.write_char('-');
- else
- /* successful transfer */
- gdb_io_ops.write_char('+');
- if (gdb_io_ops.flush)
- gdb_io_ops.flush();
- }
- } while (checksum != xmitcsum);
- }
- static void error_packet(char *pkt, int error)
- {
- error = -error;
- pkt[0] = 'E';
- pkt[1] = tohex((error / 10));
- pkt[2] = tohex((error % 10));
- pkt[3] = '\0';
- }
- #if RT_GDB_HAVE_SWBP
- static int gdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
- {
- int err;
- err = probe_kernel_write((void *)saved_instr, (void *)addr, BREAK_INSTR_SIZE);
- if (err)
- return err;
- return probe_kernel_write((void *)addr, (void *)arch_gdb_ops.gdb_bpt_instr,
- BREAK_INSTR_SIZE);
- }
- static int gdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
- {
- return probe_kernel_write((void *)addr,
- (void *)bundle, BREAK_INSTR_SIZE);
- }
- static int gdb_validate_break_address(unsigned long addr)
- {
- char tmp_variable[BREAK_INSTR_SIZE];
- int err;
- /* Validate setting the breakpoint and then removing it. In the
- * remove fails, the kernel needs to emit a bad message because we
- * are deep trouble not being able to put things back the way we
- * found them.
- */
- err = gdb_arch_set_breakpoint(addr, tmp_variable);
- if (err)
- return err;
- err = gdb_arch_remove_breakpoint(addr, tmp_variable);
- if (err)
- rt_kprintf("GDB: Critical breakpoint error,memory destroyed at: %08x \n", addr);
- return err;
- }
- /*
- * Some architectures need cache flushes when we set/clear a
- * breakpoint:
- */
- static void gdb_flush_swbreak_addr(unsigned long addr)
- {
- if (!CACHE_FLUSH_IS_SAFE)
- return;
- /* Force flush instruction cache if it was outside the mm */
- gdb_flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
- }
- /*
- * SW breakpoint management:
- */
- static int gdb_activate_sw_breakpoints(void)
- {
- unsigned long addr;
- int error = 0;
- int i;
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if (gdb_break[i].state != BP_SET)
- continue;
- addr = gdb_break[i].bpt_addr;
- error = gdb_arch_set_breakpoint(addr,
- (char *)(gdb_break[i].saved_instr));
- if (error)
- return error;
- gdb_flush_swbreak_addr(addr);
- gdb_break[i].state = BP_ACTIVE;
- }
- return 0;
- }
- int gdb_set_sw_break(unsigned long addr)
- {
- int err = gdb_validate_break_address(addr);
- int breakno = -1;
- int i;
- if (err)
- return err;
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if ((gdb_break[i].state == BP_SET) &&
- (gdb_break[i].bpt_addr == addr))
- return -1;
- }
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if (gdb_break[i].state == BP_REMOVED) {
- breakno = i;
- break;
- }
- }
- if (breakno == -1) {
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if (gdb_break[i].state == BP_UNDEFINED) {
- breakno = i;
- break;
- }
- }
- }
- if (breakno == -1)
- return -1;
- gdb_break[breakno].state = BP_SET;
- gdb_break[breakno].type = BP_BREAKPOINT;
- gdb_break[breakno].bpt_addr = addr;
- return 0;
- }
- static int gdb_deactivate_sw_breakpoints(void)
- {
- unsigned long addr;
- int error = 0;
- int i;
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if (gdb_break[i].state != BP_ACTIVE)
- continue;
- addr = gdb_break[i].bpt_addr;
- error = gdb_arch_remove_breakpoint(addr,
- (char *)(gdb_break[i].saved_instr));
- if (error)
- return error;
- gdb_flush_swbreak_addr(addr);
- gdb_break[i].state = BP_SET;
- }
- return 0;
- }
- int gdb_remove_sw_break(unsigned long addr)
- {
- int i;
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if ((gdb_break[i].state == BP_SET) &&
- (gdb_break[i].bpt_addr == addr)) {
- gdb_break[i].state = BP_REMOVED;
- return 0;
- }
- }
- return -1;
- }
- int gdb_isremovedbreak(unsigned long addr)
- {
- int i;
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if ((gdb_break[i].state == BP_REMOVED) &&
- (gdb_break[i].bpt_addr == addr))
- return 1;
- }
- return 0;
- }
- #endif
- static int remove_all_break()
- {
- #if RT_GDB_HAVE_SWBP
- unsigned long addr;
- int error=0;
- int i;
- /* Clear memory breakpoints. */
- for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) {
- if (gdb_break[i].state != BP_ACTIVE)
- goto setundefined;
- addr = gdb_break[i].bpt_addr;
- error = gdb_arch_remove_breakpoint(addr,
- (char *)gdb_break[i].saved_instr);
- if (error)
- rt_kprintf("GDB: breakpoint remove failed: %lx\n",
- addr);
- setundefined:
- gdb_break[i].state = BP_UNDEFINED;
- }
- #endif
- #if RT_GDB_HAVE_HWBP
- /* Clear hardware breakpoints. */
- arch_gdb_ops.remove_all_hw_break();
- #endif
- return 0;
- }
- static char gdbmsgbuf[BUFMAX + 1];
- static void gdb_msg_write(const char *s, int len)
- {
- char *bufptr;
- int wcount;
- int i;
- /* 'O'utput */
- gdbmsgbuf[0] = 'O';
- /* Fill and send buffers... */
- while (len > 0) {
- bufptr = gdbmsgbuf + 1;
- /* Calculate how many this time */
- if ((len << 1) > (BUFMAX - 2))
- wcount = (BUFMAX - 2) >> 1;
- else
- wcount = len;
- /* Pack in hex chars */
- for (i = 0; i < wcount; i++) {
- *(bufptr++) = tohex((s[i] >> 4) & 0xf);
- *(bufptr++) = tohex(s[i] & 0xf);
- }
- *bufptr = '\0';
- /* Move up */
- s += wcount;
- len -= wcount;
- /* Write packet */
- put_packet(gdbmsgbuf);
- }
- }
- /*
- * Return true if there is a valid gdb I/O module. Also if no
- * debugger is attached a message can be printed to the console about
- * waiting for the debugger to attach.
- *
- * The print_wait argument is only to be true when called from inside
- * the core gdb_handle_exception, because it will wait for the
- * debugger to attach.
- */
- static int gdb_io_ready(int print_wait)
- {
- if (!gdb_dev)
- return 0;
- if (gdb_connected)
- return 1;
- if (print_wait)
- rt_kprintf("GDB: Waiting for remote debugger\n");
- return 1;
- }
- /* Handle the '?' status packets */
- static void gdb_cmd_status(struct gdb_state *gs)
- {
- /*
- * We know that this packet is only sent
- * during initial connect. So to be safe,
- * we clear out our breakpoints now in case
- * GDB is reconnecting.
- */
- remove_all_break();
- remcom_out_buffer[0] = 'S';
- remcom_out_buffer[1] = tohex((gs->signo >> 4) &0xf);
- remcom_out_buffer[2] = tohex(gs->signo & 0xf);
- remcom_out_buffer[3] = 0;
- }
- /* Handle the 'm' memory read bytes */
- static void gdb_cmd_memread(struct gdb_state *gs)
- {
- char *ptr = &remcom_in_buffer[1];
- unsigned long length;
- unsigned long addr;
- int err;
- if (gdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
- gdb_hex2long(&ptr, &length) > 0) {
- #ifdef GDB_DATA_ACCESS
- //accesses to areas not backed can cause error
- if (gdb_permit_data_access(addr, length))
- return ;
- #endif
- err = gdb_mem2hex((char *)addr, remcom_out_buffer, length);
- if (err)
- error_packet(remcom_out_buffer, err);
- } else {
- error_packet(remcom_out_buffer, -1);
- }
- }
- /* Handle the 'M' memory write bytes */
- static void gdb_cmd_memwrite(struct gdb_state *gs)
- {
- int err = write_mem_msg(0);
- if (err)
- error_packet(remcom_out_buffer, err);
- else
- strcpy(remcom_out_buffer, "OK");
- }
- /* Handle the 'X' memory binary write bytes */
- static void gdb_cmd_binwrite(struct gdb_state *gs)
- {
- int err = write_mem_msg(1);
- if (err)
- error_packet(remcom_out_buffer, err);
- else
- strcpy(remcom_out_buffer, "OK");
- }
- /* Handle the 'q' query packets */
- static void gdb_cmd_query(struct gdb_state *gs)
- {
- /* nothing,because we have no thread support */
- }
- /* Handle the 'g' or 'p' get registers request */
- static void gdb_cmd_getregs(struct gdb_state *gs)
- {
- char len = sizeof(long);
- gdb_get_register((unsigned long *)gdb_regs);
- /*get one registers*/
- if (remcom_in_buffer[0] == 'p'){
- char *p = &remcom_in_buffer[1];
- unsigned long regno = 0;
- if (gdb_hex2long(&p, ®no)){
- gdb_mem2hex(((char *)gdb_regs) + regno * len, remcom_out_buffer, len);
- return;
- } else {
- strcpy(remcom_out_buffer, "INVALID");
- return;
- }
- }
- gdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES);
- }
- /* Handle the 'G' or 'P' set registers request */
- static void gdb_cmd_setregs(struct gdb_state *gs)
- {
- char len = sizeof(long);
- /*set one registers*/
- if (remcom_in_buffer[0] == 'P'){
- char *p = &remcom_in_buffer[1];
- unsigned long regno = 0;
- if (gdb_hex2long(&p, ®no) && *p++ == '='){
- gdb_get_register((unsigned long *)gdb_regs);
- gdb_hex2mem(p, ((char *)gdb_regs) + regno * len, len);
- gdb_put_register(gdb_regs);
- strcpy(remcom_out_buffer, "OK");
- }
- return;
- }
- gdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES);
- gdb_put_register(gdb_regs);
- strcpy(remcom_out_buffer, "OK");
- }
- /* Handle the 'D' or 'k', detach or kill packets */
- static void gdb_cmd_detachkill(struct gdb_state *gs)
- {
- int error;
- /* The detach case */
- if (remcom_in_buffer[0] == 'D') {
- error = remove_all_break();
- if (error < 0) {
- error_packet(remcom_out_buffer, error);
- } else {
- strcpy(remcom_out_buffer, "OK");
- gdb_connected = 0;
- }
- put_packet(remcom_out_buffer);
- } else {
- /*
- * Assume the kill case, with no exit code checking,
- * trying to force detach the debugger:
- */
- remove_all_break();
- gdb_connected = 0;
- }
- }
- /* Handle the 'z' or 'Z' breakpoint remove or set packets */
- static void gdb_cmd_break(struct gdb_state *gs)
- {
- /*
- * Since GDB-5.3, it's been drafted that '0' is a software
- * breakpoint, '1' is a hardware breakpoint, so let's do that.
- */
- char *bpt_type = &remcom_in_buffer[1];
- char *ptr = &remcom_in_buffer[2];
- unsigned long addr;
- unsigned long length;
- int error = 0;
- if (arch_gdb_ops.set_hw_breakpoint && *bpt_type >= '1') {
- /* Unsupported */
- if (*bpt_type > '4')
- return;
- }
- /*
- * Test if this is a hardware breakpoint, and
- * if we support it:
- */
- if (*bpt_type == '1' && !(arch_gdb_ops.flags)) {
- /* Unsupported. */
- return;
- }
- if (*(ptr++) != ',') {
- error_packet(remcom_out_buffer, -1);
- return;
- }
- if (!gdb_hex2long(&ptr, &addr)) {
- error_packet(remcom_out_buffer, -1);
- return;
- }
- if (*(ptr++) != ',' ||
- !gdb_hex2long(&ptr, &length)) {
- error_packet(remcom_out_buffer, -1);
- return;
- }
- #if RT_GDB_HAVE_SWBP
- if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')
- error = gdb_set_sw_break(addr);
- else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
- error = gdb_remove_sw_break(addr);
- #else
- if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0')
- error = arch_gdb_ops.set_hw_breakpoint(addr,
- (int)length, BP_HARDWARE_BREAKPOINT);
- else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
- error = arch_gdb_ops.remove_hw_breakpoint(addr,
- (int) length, BP_HARDWARE_BREAKPOINT);
- #endif
- else if (remcom_in_buffer[0] == 'Z')
- error = arch_gdb_ops.set_hw_breakpoint(addr,
- (int)length, *bpt_type - '0');
- else if (remcom_in_buffer[0] == 'z')
- error = arch_gdb_ops.remove_hw_breakpoint(addr,
- (int) length, *bpt_type - '0');
- if (error == 0)
- strcpy(remcom_out_buffer, "OK");
- else
- error_packet(remcom_out_buffer, error);
- }
- /* Handle the 'C' signal / exception passing packets */
- static int gdb_cmd_exception_pass(struct gdb_state *gs)
- {
- /* C09 == pass exception
- * C15 == detach gdb, pass exception
- */
- if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') {
- gs->pass_exception = 1;
- remcom_in_buffer[0] = 'c';
- } else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') {
- gs->pass_exception = 1;
- remcom_in_buffer[0] = 'D';
- remove_all_break();
- gdb_connected = 0;
- return 1;
- } else {
- error_packet(remcom_out_buffer, -1);
- return 0;
- }
- /* Indicate fall through */
- return -1;
- }
- /*more about packet in https://www.sourceware.org/gdb/current/onlinedocs/gdb/Packets.html#Packets*/
- static int process_packet(char *pkt)
- {
- int status = 0;
- int tmp;
- status = gdb_arch_handle_exception(remcom_in_buffer,
- remcom_out_buffer);
- remcom_out_buffer[0] = 0;
- switch (pkt[0]) {
- case '?':/* gdbserial status */
- gdb_cmd_status(&gs);
- break;
- case 'q':/* query command */
- gdb_cmd_query(&gs);
- break;
- case 'p': /* return the value of a single CPU register */
- case 'g': /* return the value of the CPU registers */
- gdb_cmd_getregs(&gs);
- break;
- case 'P': /* set the value of a single CPU registers - return OK */
- case 'G': /* set the value of the CPU registers - return OK */
- gdb_cmd_setregs(&gs);
- break;
- case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
- gdb_cmd_memread(&gs);
- break;
- case 'X':/* XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA*/
- gdb_cmd_binwrite(&gs);
- break;
- case 'M':/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
- gdb_cmd_memwrite(&gs);
- break;
- case 'D': /* Debugger detach */
- case 'k': /* Debugger detach via kill */
- gdb_cmd_detachkill(&gs);
- break;
- case 'C':/* Exception passing */
- tmp = gdb_cmd_exception_pass(&gs);
- if (tmp > 0)
- process_packet(remcom_in_buffer);
- if (tmp == 0)
- break;
- case 'z':/* Break point remove */
- case 'Z':/* Break point set */
- gdb_cmd_break(&gs);
- break;
- case 'H':/* task related */
- break;
- case 'T':/* Query thread status */
- break;
- case 'b': /* bBB... Set baud rate to BB... */
- break;
- case 's': /* sAA..AA step form address AA..AA (optional) */
- case 'c': /* cAA..AA Continue at address AA..AA (optional) */
- #if RT_GDB_HAVE_SWBP
- gdb_activate_sw_breakpoints();
- #endif
- break;
- }
- if (!status)
- return -1;
- exit:
- put_packet(remcom_out_buffer);
- return 0;
- }
- /*
- * This function does all command procesing for interfacing to gdb.
- */
- int gdb_process_exception()
- {
- int status;
- do {
- get_packet(remcom_in_buffer);
- status = process_packet(remcom_in_buffer);
- } while (status == 0);
- if (status < 0)
- return 0;
- else
- return 1;
- }
- int gdb_handle_exception(int signo, void *regs)
- {
- int error;
- gs.signo = signo;
- if (!gdb_io_ready(1)) {
- error = 1;
- return error; /* No I/O connection, so resume the system */
- }
- #if RT_GDB_HAVE_SWBP
- gdb_deactivate_sw_breakpoints();
- #endif
- gdb_set_register(regs);
- /* Clear the out buffer. */
- memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
-
- if (gdb_connected) {
- char *ptr;
- gdb_io_ops.write_char('\n');
- /* Reply to host that an exception has occurred */
- ptr = remcom_out_buffer;
- *ptr++ = 'T';
- *ptr++ = tohex((gs.signo >> 4) &0xf);
- *ptr++ = tohex(gs.signo & 0xf);
- /*ptr += strlen(strcpy(ptr, "thread:"));*/
- /**ptr++ = ';';*/
- put_packet(remcom_out_buffer);
- }
- gs.pass_exception = 0;
- while (gdb_process_exception());
- error = gs.pass_exception;
- return error;
- }
- void gdb_console_write(const char *s, unsigned count)
- {
- /* If we're debugging, or GDB has not connected, don't try
- * and print. */
- if (!gdb_connected)
- return;
- gdb_msg_write(s, count);
- }
|