未验证 提交 def7bd4c 编写于 作者: B Bernard Xiong 提交者: GitHub

Merge pull request #1957 from RT-Thread/remove_gdbstub

Remove gdbstub
Import('rtconfig')
from building import *
src = Glob('*.c')
comm = 'libcpu/' + rtconfig.ARCH
if (rtconfig.CPU == 'cortex-m4') or (rtconfig.CPU == 'cortex-m3'):
comm = 'libcpu/cortexm'
cwd = GetCurrentDir()
if rtconfig.PLATFORM == 'armcc':
src = src + Glob(comm + '/*.c') + Glob(comm + '/*_rvds.S')
if rtconfig.PLATFORM == 'gcc':
src = src + Glob(comm + '/*.c') + Glob(comm + '/*_gcc.S')
if rtconfig.PLATFORM == 'iar':
src = src + Glob(comm + '/*.c') + Glob(comm + '/*_iar.S')
CPPPATH = [cwd, cwd + '/' + comm]
group = DefineGroup('gdb', src, depend = ['RT_USING_GDB'], CPPPATH = CPPPATH)
Return('group')
/*
* 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, &regno)){
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, &regno) && *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);
}
/*
* This provides the functions that GDB needs to share between
* different portions.
*
* GDB stub.
*
* Migarte form linux to rt-thread by Wzyy2
* Original edition : KGDB stub
*
* File : gdb_stub.h
* 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
*/
#ifndef __GDB_STUB_H__
#define __GDB_STUB_H__
#include <rtthread.h>
#include <arch_gdb.h>
#ifndef RT_GDB_MAX_BREAKPOINTS
#define GDB_MAX_BREAKPOINTS 20
#else
#define GDB_MAX_BREAKPOINTS RT_GDB_MAX_BREAKPOINTS
#endif
// Signal definitions
#define SIGHUP 1 /* hangup */
#define SIGINT 2 /* interrupt */ //irq or fiq
#define SIGQUIT 3 /* quit */
#define SIGILL 4 /* illegal instruction (not reset when caught) */
#define SIGTRAP 5 /* trace trap (not reset when caught) */
#define SIGIOT 6 /* IOT instruction */
#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */
#define SIGEMT 7 /* EMT instruction */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
#define SIGBUS 10 /* bus error */ //abort or reserved
#define SIGSEGV 11 /* segmentation violation */
#define SIGSYS 12 /* bad argument to system call */
#define SIGPIPE 13 /* write on a pipe with no one to read it */
#define SIGALRM 14 /* alarm clock */
#define SIGTERM 15 /* software termination signal from kill */
enum gdb_bptype {
BP_BREAKPOINT = 0,
BP_HARDWARE_BREAKPOINT,
BP_WRITE_WATCHPOINT,
BP_READ_WATCHPOINT,
BP_ACCESS_WATCHPOINT,
BP_POKE_BREAKPOINT,
};
enum gdb_bpstate {
BP_UNDEFINED = 0,
BP_REMOVED,
BP_SET,
BP_ACTIVE
};
struct gdb_bkpt {
unsigned long bpt_addr;
unsigned char saved_instr[BREAK_INSTR_SIZE];
enum gdb_bptype type;
enum gdb_bpstate state;
};
/**
* struct gdb_arch - Describe architecture specific values.
* @gdb_bpt_instr: The instruction to trigger a breakpoint.
* @flags: Flags for the breakpoint, currently just %GDB_HW_BREAKPOINT.
* @set_hw_breakpoint: Allow an architecture to specify how to set a hardware
* breakpoint.
* @remove_hw_breakpoint: Allow an architecture to specify how to remove a
* hardware breakpoint.
* @remove_all_hw_break: Allow an architecture to specify how to remove all
* hardware breakpoints.
*/
struct gdb_arch {
unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
unsigned long flags;
int (*set_hw_breakpoint)(unsigned long, int, enum gdb_bptype);
int (*remove_hw_breakpoint)(unsigned long, int, enum gdb_bptype);
void (*remove_all_hw_break)(void);
};
/**
* struct gdb_io - Describe the interface for an I/O driver to talk with KGDB.
* @read_char: Pointer to a function that will return one char.
* @write_char: Pointer to a function that will write one char.
* @flush: Pointer to a function that will flush any pending writes.
* @init: Pointer to a function that will initialize the device.
*/
struct gdb_io {
int (*read_char) (void);
void (*write_char) (char);
void (*flush) (void);
int (*init) (void);
};
extern int gdb_connected;
extern void* volatile gdb_mem_fault_handler;
int gdb_hex2long(char **ptr, unsigned long *long_val);
int gdb_mem2hex(char *mem, char *buf, int count);
int gdb_hex2mem(char *buf, char *mem, int count);
int gdb_ebin2mem(char *buf, char *mem, int count);
int gdb_set_sw_break(unsigned long addr);
int gdb_remove_sw_break(unsigned long addr);
int gdb_isremovedbreak(unsigned long addr);
void gdb_console_write(const char *s, unsigned count);
int gdb_handle_exception(int signo, void *regs);
/* hal */
extern struct gdb_io gdb_io_ops;
extern rt_device_t gdb_dev;
void gdb_start();
void gdb_set_device(const char* device_name);
#endif /* __GDB_STUB_H__ */
/*
* I/O and interface portion of GDB stub
*
* File : hal_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
*/
#include <rtthread.h>
#include <rthw.h>
#include "gdb_stub.h"
#ifdef RT_USING_SERIAL
#include <rtdevice.h>
#endif
rt_device_t gdb_dev = RT_NULL;
static struct rt_serial_device *gdb_serial;
char gdb_io_set;
void gdb_uart_putc(char c);
int gdb_uart_getc();
/*if you want to use something instead of the serial,change it */
struct gdb_io gdb_io_ops = {
gdb_uart_getc,
gdb_uart_putc
};
/**
* @ingroup gdb_stub
*
* This function will get GDB stubs started, with a proper environment
*/
void gdb_start()
{
if (gdb_dev == RT_NULL)
rt_kprintf("GDB: no gdb_dev found,please set it first\n");
else
gdb_breakpoint();
}
/**
* @ingroup gdb_stub
*
* This function sets the input device of gdb_stub.
*
* @param device_name the name of new input device.
*/
void gdb_set_device(const char* device_name)
{
rt_device_t dev = RT_NULL;
dev = rt_device_find(device_name);
if(dev == RT_NULL){
rt_kprintf("GDB: can not find device: %s\n", device_name);
return;
}
/* open this device and set the new device */
if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM) == RT_EOK)
{
gdb_dev = dev;
gdb_serial = (struct rt_serial_device *)gdb_dev;
}
}
void gdb_uart_putc(char c)
{
#ifdef RT_GDB_DEBUG
rt_kprintf("%c",c);
#endif
rt_device_write(gdb_dev, 0, &c, 1);
}
/* polling */
int gdb_uart_getc()
{
int ch;
#ifdef RT_USING_SERIAL
ch = -1;
do {
ch = gdb_serial->ops->getc(gdb_serial);
} while (ch == -1);
#else
rt_device_read(gdb_dev, 0, &ch, 1);
#endif
#ifdef RT_GDB_DEBUG
rt_kprintf("%c",ch);
#endif
return ch;
}
/*
* ARM GDB support
* arch-specific portion of GDB stub
*
* File : arch_gdb.h(arm)
* 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
*/
#ifndef __ARM_GDB_H__
#define __ARM_GDB_H__
#include <rtthread.h>
#ifndef RT_GDB_HAVE_HWBP
#define RT_GDB_HAVE_HWBP 0
#endif
#ifndef RT_GDB_HAVE_SWBP
#define RT_GDB_HAVE_SWBP 1
#endif
#if RT_GDB_HAVE_HWBP
#error GDB:No hardware_breakpoint support
#endif
/*
* By doing this as an undefined instruction trap, we force a mode
* switch from SVC to UND mode, allowing us to save full kernel state.
* We also define a GDB_COMPILED_BREAK which can be used to compile
* in breakpoints.
*/
#define BREAK_INSTR_SIZE 4
#define GDB_BREAKINST 0xe7ffdefe
#define GDB_COMPILED_BREAK 0xe7ffdeff
#define CACHE_FLUSH_IS_SAFE 1
#define ARM_GP_REGS 16
#define ARM_FP_REGS 8
#define ARM_EXTRA_REGS 2
#define GDB_MAX_REGS (ARM_GP_REGS + (ARM_FP_REGS * 3) + ARM_EXTRA_REGS)
#define NUMREGBYTES (GDB_MAX_REGS << 2)
//#define BUFMAX ((NUMREGBYTES << 1) + 10)
#define BUFMAX 400
enum regnames {
GDB_R0, /*0*/
GDB_R1, /*1*/
GDB_R2, /*2*/
GDB_R3, /*3*/
GDB_R4, /*4*/
GDB_R5, /*5*/
GDB_R6, /*6*/
GDB_R7, /*7*/
GDB_R8, /*8*/
GDB_R9, /*9*/
GDB_R10, /*10*/
GDB_FP, /*11*/
GDB_IP, /*12*/
GDB_SPT, /*13*/
GDB_LR, /*14*/
GDB_PC, /*15*/
GDB_CPSR = GDB_MAX_REGS-1
};
/* arch */
extern struct gdb_arch arch_gdb_ops;
void gdb_breakpoint();
void gdb_get_register(unsigned long *gdb_regs);
void gdb_put_register(unsigned long *gdb_regs);
void gdb_set_register(void *hw_regs);
int gdb_arch_handle_exception(char *remcom_in_buffer,
char *remcom_out_buffer);
void gdb_flush_icache_range(unsigned long start, unsigned long end);
int gdb_undef_hook(void *regs);
int gdb_handle_exception(int signo, void *regs);
#endif /* __ARM_GDB_H__ */
/*
* ARM GDB support
* arch-specific portion of GDB stub
*
* File : arm_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
*/
#include <rtthread.h>
#include <rthw.h>
#include <gdb_stub.h>
#include <arch_gdb.h>
#define PS_N 0x80000000
#define PS_Z 0x40000000
#define PS_C 0x20000000
#define PS_V 0x10000000
#define IS_THUMB_ADDR(addr) ((addr) & 1)
#define MAKE_THUMB_ADDR(addr) ((addr) | 1)
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
static int compiled_break = 0;
static unsigned long step_addr = 0;
static int ins_will_execute(unsigned long ins);
static unsigned long target_ins(unsigned long *pc, unsigned long ins);
/*struct gdb_arch - Describe architecture specific values.*/
struct gdb_arch arch_gdb_ops = {
.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} //Little-Endian
};
struct rt_gdb_register
{
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t fp;
rt_uint32_t ip;
rt_uint32_t sp;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t cpsr;
rt_uint32_t ORIG_r0;
}*regs;
/**
* gdb_breakpoint - generate a compiled_breadk
* It is used to sync up with a debugger and stop progarm
*/
void gdb_breakpoint()
{
asm(".word 0xe7ffdeff");
}
void gdb_set_register(void *hw_regs)
{
regs = (struct rt_gdb_register *)hw_regs;
}
void gdb_get_register(unsigned long *gdb_regs)
{
int regno;
/* Initialize all to zero. */
for (regno = 0; regno < GDB_MAX_REGS; regno++)
gdb_regs[regno] = 0;
gdb_regs[GDB_R0] = regs->r0;
gdb_regs[GDB_R1] = regs->r1;
gdb_regs[GDB_R2] = regs->r2;
gdb_regs[GDB_R3] = regs->r3;
gdb_regs[GDB_R4] = regs->r4;
gdb_regs[GDB_R5] = regs->r5;
gdb_regs[GDB_R6] = regs->r6;
gdb_regs[GDB_R7] = regs->r7;
gdb_regs[GDB_R8] = regs->r8;
gdb_regs[GDB_R9] = regs->r9;
gdb_regs[GDB_R10] = regs->r10;
gdb_regs[GDB_FP] = regs->fp;
gdb_regs[GDB_IP] = regs->ip;
gdb_regs[GDB_SPT] = regs->sp;
gdb_regs[GDB_LR] = regs->lr;
gdb_regs[GDB_PC] = regs->pc;
gdb_regs[GDB_CPSR] = regs->cpsr;
};
void gdb_put_register(unsigned long *gdb_regs)
{
regs->r0 = gdb_regs[GDB_R0];
regs->r1 = gdb_regs[GDB_R1];
regs->r2 = gdb_regs[GDB_R2];
regs->r3 = gdb_regs[GDB_R3];
regs->r4 = gdb_regs[GDB_R4];
regs->r5 = gdb_regs[GDB_R5];
regs->r6 = gdb_regs[GDB_R6];
regs->r7 = gdb_regs[GDB_R7];
regs->r8 = gdb_regs[GDB_R8];
regs->r9 = gdb_regs[GDB_R9];
regs->r10 = gdb_regs[GDB_R10];
regs->fp = gdb_regs[GDB_FP];
regs->ip = gdb_regs[GDB_IP];
regs->sp = gdb_regs[GDB_SPT];
regs->lr = gdb_regs[GDB_LR];
regs->pc = gdb_regs[GDB_PC];
regs->cpsr = gdb_regs[GDB_CPSR];
}
/* It will be called during process_packet */
int gdb_arch_handle_exception(char *remcom_in_buffer,
char *remcom_out_buffer)
{
unsigned long addr,curins;
char *ptr;
/*clear single step*/
if (step_addr) {
gdb_remove_sw_break(step_addr);
step_addr = 0;
}
switch (remcom_in_buffer[0]) {
case 'D':
case 'k':
case 'c':
/*
* If this was a compiled breakpoint, we need to move
* to the next instruction or we will breakpoint
* over and over again
*/
ptr = &remcom_in_buffer[1];
if (gdb_hex2long(&ptr, &addr))
regs->pc = addr;
else if (compiled_break == 1)
regs->pc += 4;
compiled_break = 0;
return 0;
case 's':
ptr = &remcom_in_buffer[1];
if (gdb_hex2long(&ptr, &addr))
regs->pc = addr;
curins = *(unsigned long*)(regs->pc);
if (ins_will_execute(curins))
//Decode instruction to decide what the next pc will be
step_addr = target_ins((unsigned long *)regs->pc, curins);
else
step_addr = regs->pc + 4;
#ifdef RT_GDB_DEBUG
rt_kprintf("\n next will be %x \n",step_addr);
#endif
gdb_set_sw_break(step_addr);
if (compiled_break == 1)
regs->pc += 4;
compiled_break = 0;
return 0;
}
return -1;
}
/* flush icache to let the sw breakpoint working */
void gdb_flush_icache_range(unsigned long start, unsigned long end)
{
#ifdef RT_GDB_ICACHE
extern void mmu_invalidate_icache();
mmu_invalidate_icache(); //for arm,wo can only invalidate it
#endif
}
/* register a hook in undef*/
int gdb_undef_hook(void *regs)
{
struct rt_gdb_register *tmp_reg = (struct rt_gdb_register *)regs;
unsigned long *tmp_pc = (unsigned long *)tmp_reg->pc;
/* it is a compiled break */
if (*tmp_pc == GDB_COMPILED_BREAK) {
compiled_break = 1;
gdb_handle_exception(SIGTRAP, regs);
return 1;
}
/* it is a sw break */
else if (*tmp_pc == GDB_BREAKINST) {
gdb_handle_exception(SIGTRAP, regs);
return 1;
}
/*or we just go */
return 0;
}
static unsigned long gdb_arch_regs[GDB_MAX_REGS];
static int ins_will_execute(unsigned long ins)
{
unsigned long psr = regs->cpsr; // condition codes
int res = 0;
switch ((ins & 0xF0000000) >> 28) {
case 0x0: // EQ
res = (psr & PS_Z) != 0;
break;
case 0x1: // NE
res = (psr & PS_Z) == 0;
break;
case 0x2: // CS
res = (psr & PS_C) != 0;
break;
case 0x3: // CC
res = (psr & PS_C) == 0;
break;
case 0x4: // MI
res = (psr & PS_N) != 0;
break;
case 0x5: // PL
res = (psr & PS_N) == 0;
break;
case 0x6: // VS
res = (psr & PS_V) != 0;
break;
case 0x7: // VC
res = (psr & PS_V) == 0;
break;
case 0x8: // HI
res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0);
break;
case 0x9: // LS
res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0);
break;
case 0xA: // GE
res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
((psr & (PS_N|PS_V)) == 0);
break;
case 0xB: // LT
res = ((psr & (PS_N|PS_V)) == PS_N) ||
((psr & (PS_N|PS_V)) == PS_V);
break;
case 0xC: // GT
res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
((psr & (PS_N|PS_V)) == 0);
res = ((psr & PS_Z) == 0) && res;
break;
case 0xD: // LE
res = ((psr & (PS_N|PS_V)) == PS_N) ||
((psr & (PS_N|PS_V)) == PS_V);
res = ((psr & PS_Z) == PS_Z) || res;
break;
case 0xE: // AL
res = 1;
break;
case 0xF: // NV
if (((ins & 0x0E000000) >> 24) == 0xA)
res = 1;
else
res = 0;
break;
}
return res;
}
static unsigned long RmShifted(int shift)
{
unsigned long Rm = gdb_arch_regs[shift & 0x00F];
int shift_count;
if ((shift & 0x010) == 0) {
shift_count = (shift & 0xF80) >> 7;
} else {
shift_count = gdb_arch_regs[(shift & 0xF00) >> 8];
}
switch ((shift & 0x060) >> 5) {
case 0x0: // Logical left
Rm <<= shift_count;
break;
case 0x1: // Logical right
Rm >>= shift_count;
break;
case 0x2: // Arithmetic right
Rm = (unsigned long)((long)Rm >> shift_count);
break;
case 0x3: // Rotate right
if (shift_count == 0) {
// Special case, RORx
Rm >>= 1;
if (gdb_arch_regs[GDB_CPSR] & PS_C) Rm |= 0x80000000;
} else {
Rm = (Rm >> shift_count) | (Rm << (32-shift_count));
}
break;
}
return Rm;
}
// Decide the next instruction to be executed for a given instruction
static unsigned long target_ins(unsigned long *pc, unsigned long ins)
{
unsigned long new_pc, offset, op2;
unsigned long Rn;
int i, reg_count, c;
gdb_get_register(gdb_arch_regs);
switch ((ins & 0x0C000000) >> 26) {
case 0x0:
// BX or BLX
if ((ins & 0x0FFFFFD0) == 0x012FFF10) {
new_pc = (unsigned long)gdb_arch_regs[ins & 0x0000000F];
return new_pc;
}
// Data processing
new_pc = (unsigned long)(pc+1);
if ((ins & 0x0000F000) == 0x0000F000) {
// Destination register is PC
if ((ins & 0x0FBF0000) != 0x010F0000) {
Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16];
if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
if ((ins & 0x02000000) == 0) {
op2 = RmShifted(ins & 0x00000FFF);
} else {
op2 = ins & 0x000000FF;
i = (ins & 0x00000F00) >> 8; // Rotate count
op2 = (op2 >> (i*2)) | (op2 << (32-(i*2)));
}
switch ((ins & 0x01E00000) >> 21) {
case 0x0: // AND
new_pc = Rn & op2;
break;
case 0x1: // EOR
new_pc = Rn ^ op2;
break;
case 0x2: // SUB
new_pc = Rn - op2;
break;
case 0x3: // RSB
new_pc = op2 - Rn;
break;
case 0x4: // ADD
new_pc = Rn + op2;
break;
case 0x5: // ADC
c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0;
new_pc = Rn + op2 + c;
break;
case 0x6: // SBC
c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0;
new_pc = Rn - op2 + c - 1;
break;
case 0x7: // RSC
c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0;
new_pc = op2 - Rn +c - 1;
break;
case 0x8: // TST
case 0x9: // TEQ
case 0xA: // CMP
case 0xB: // CMN
break; // PC doesn't change
case 0xC: // ORR
new_pc = Rn | op2;
break;
case 0xD: // MOV
new_pc = op2;
break;
case 0xE: // BIC
new_pc = Rn & ~op2;
break;
case 0xF: // MVN
new_pc = ~op2;
break;
}
}
}
return new_pc;
case 0x1:
if ((ins & 0x02000010) == 0x02000010) {
// Undefined!
return (unsigned long)(pc+1);
} else {
if ((ins & 0x00100000) == 0) {
// STR
return (unsigned long)(pc+1);
} else {
// LDR
if ((ins & 0x0000F000) != 0x0000F000) {
// Rd not PC
return (unsigned long)(pc+1);
} else {
Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16];
if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
if (ins & 0x01000000) {
// Add/subtract offset before
if ((ins & 0x02000000) == 0) {
// Immediate offset
if (ins & 0x00800000) {
// Add offset
Rn += (ins & 0x00000FFF);
} else {
// Subtract offset
Rn -= (ins & 0x00000FFF);
}
} else {
// Offset is in a register
if (ins & 0x00800000) {
// Add offset
Rn += RmShifted(ins & 0x00000FFF);
} else {
// Subtract offset
Rn -= RmShifted(ins & 0x00000FFF);
}
}
}
return *(unsigned long *)Rn;
}
}
}
return (unsigned long)(pc+1);
case 0x2: // Branch, LDM/STM
if ((ins & 0x02000000) == 0) {
// LDM/STM
if ((ins & 0x00100000) == 0) {
// STM
return (unsigned long)(pc+1);
} else {
// LDM
if ((ins & 0x00008000) == 0) {
// PC not in list
return (unsigned long)(pc+1);
} else {
Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16];
if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
offset = ins & 0x0000FFFF;
reg_count = 0;
for (i = 0; i < 15; i++) {
if (offset & (1<<i)) reg_count++;
}
if (ins & 0x00800000) {
// Add offset
Rn += reg_count*4;
} else {
// Subtract offset
Rn -= 4;
}
return *(unsigned long *)Rn;
}
}
} else {
// Branch
if (ins_will_execute(ins)) {
offset = (ins & 0x00FFFFFF) << 2;
if (ins & 0x00800000)
offset |= 0xFC000000; // sign extend
new_pc = (unsigned long)(pc+2) + offset;
// If its BLX, make new_pc a thumb address.
if ((ins & 0xFE000000) == 0xFA000000) {
if ((ins & 0x01000000) == 0x01000000)
new_pc |= 2;
new_pc = MAKE_THUMB_ADDR(new_pc);
}
return new_pc;
} else {
// Falls through
return (unsigned long)(pc+1);
}
}
case 0x3: // Coprocessor & SWI
if (((ins & 0x03000000) == 0x03000000) && ins_will_execute(ins)) {
// SWI
// TODO(wzyy2) some problems.
extern unsigned long vector_swi;
return vector_swi;
} else {
return (unsigned long)(pc+1);
}
default:
// Never reached - but fixes compiler warning.
return 0;
}
}
/*
* CORTEXM GDB support
* arch-specific portion of GDB stub
*
* File : arch_gdb.h(cortexm)
* 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
*/
#ifndef __ARM_GDB_H__
#define __ARM_GDB_H__
#include <rtthread.h>
#ifndef RT_GDB_HAVE_HWBP
#define RT_GDB_HAVE_HWBP 1
#endif
#ifndef RT_GDB_HAVE_SWBP
#define RT_GDB_HAVE_SWBP 0
#endif
#ifndef GDB_CORTEXM_PRIORITY_MAX
#define GDB_CORTEXM_PRIORITY_MAX (1 << 6)
#endif
#define GDB_DATA_ACCESS
#define BREAK_INSTR_SIZE 4
#define ARM_GP_REGS 16
#define ARM_FP_REGS 8
#define ARM_EXTRA_REGS 2
#define GDB_MAX_REGS (ARM_GP_REGS + (ARM_FP_REGS * 3) + ARM_EXTRA_REGS)
#define NUMREGBYTES (GDB_MAX_REGS << 2)
#define HBP_NUM 6 //Max hardware breakpoint
#define HWP_NUM 4 //Max hardware watchpoint
//#define BUFMAX ((NUMREGBYTES << 1) + 10)
#define BUFMAX 400
#define GDB_DEBUG_REG_BASE 0xE000EDF0
#define GDB_DEBUG_REG_DHSR 0x00
#define GDB_DEBUG_REG_DCRSR 0x04
#define GDB_DEBUG_REG_DCRDR 0x08
#define GDB_DEBUG_REG_DEMCR 0x0c
#define GDB_DEBUG_REG_DEMCR_MON_EN (1UL << 16)
#define GDB_DEBUG_REG_DEMCR_MON_PEND (1UL << 17)
#define GDB_DEBUG_REG_DEMCR_MON_STEP (1UL << 18)
#define GDB_DEBUG_REG_DEMCR_TRCENA (1UL << 24)
#define GDB_NVIC_REG_BASE 0xE000E000
#define GDB_NVIC_REG_SHCSR 0xD24
#define GDB_NVIC_REG_DFSR 0xD30
#define GDB_NVIC_REG_SHCSR_MEMFAULTENA (1 << 16)
#define GDB_FPB_REG_BASE 0xE0002000
#define GDB_FPB_REG_CTRL 0x0
#define GDB_FPB_REG_REMAP 0x4
#define GDB_FPB_REG_COMP 0x8
#define GDB_FPB_REG_CTRL_KEY (1UL << 1)
#define GDB_FPB_REG_CTRL_ENABLE 1
#define GDB_FPB_REG_COMP_ENABLE 1
#define GDB_FPB_REG_COMP_ADDR (((1UL << 29) -1) << 2)
#define GDB_FPB_REG_COMP_REPLACE (((1UL << 32) -1) << 30)
#define GDB_DWT_REG_BASE 0xE0001000
#define GDB_DWT_REG_CTRL 0x0
#define GDB_DWT_REG_COMP 0x20
#define GDB_DWT_REG_MASK 0x24
#define GDB_DWT_REG_FUNCTION 0x28
#define GDB_DWT_REG_FUNCTION_FUC (((1UL << 4) -1) << 0)
enum regnames {
GDB_R0, /*0*/
GDB_R1, /*1*/
GDB_R2, /*2*/
GDB_R3, /*3*/
GDB_R4, /*4*/
GDB_R5, /*5*/
GDB_R6, /*6*/
GDB_R7, /*7*/
GDB_R8, /*8*/
GDB_R9, /*9*/
GDB_R10, /*10*/
GDB_FP, /*11*/
GDB_IP, /*12*/
GDB_SPT, /*13*/
GDB_LR, /*14*/
GDB_PC, /*15*/
GDB_F0, /*16*/
GDB_F1, /*17*/
GDB_F2, /*18*/
GDB_F3, /*19*/
GDB_F4, /*20*/
GDB_F5, /*21*/
GDB_F6, /*22*/
GDB_F7, /*23*/
GDB_FPS, /*24*/
GDB_CPSR = GDB_MAX_REGS-1
};
typedef struct
{
unsigned long type; // State type
unsigned long vector; // Exception vector number
unsigned long basepri; // BASEPRI
unsigned long r4; // Remaining CPU registers
unsigned long r5; // Remaining CPU registers
unsigned long r6; // Remaining CPU registers
unsigned long r7; // Remaining CPU registers
unsigned long r8; // Remaining CPU registers
unsigned long r9; // Remaining CPU registers
unsigned long r10; // Remaining CPU registers
unsigned long r11; // Remaining CPU registers
unsigned long sp; // Remaining CPU registers
unsigned long xlr; // Exception return LR
// The following are saved and restored automatically by the CPU
// for exceptions or interrupts.
unsigned long r0;
unsigned long r1;
unsigned long r2;
unsigned long r3;
unsigned long r12;
unsigned long lr;
unsigned long pc;
unsigned long psr;
} Gdb_SavedRegisters;
/* arch */
extern struct gdb_arch arch_gdb_ops;
void gdb_breakpoint();
void gdb_get_register(unsigned long *gdb_regs);
void gdb_put_register(unsigned long *gdb_regs);
void gdb_set_register(void *hw_regs);
int gdb_arch_handle_exception(char *remcom_in_buffer,
char *remcom_out_buffer);
int gdb_permit_data_access(unsigned long addr, unsigned long count);
void gdb_arch_exit();
void gdb_arch_late();
#endif /* __CORTEXM_GDB_H__ */
/*
* CORTEXM GDB support
* arch-specific portion of GDB stub
*
* File : cortexm_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
*/
#include <rtthread.h>
#include <rthw.h>
#include <gdb_stub.h>
static Gdb_SavedRegisters *regs;
unsigned long single_step_basepri = 0;
void gdb_remove_all_hw_break();
void gdb_enable_hw_debug();
void gdb_disable_hw_debug();
int gdb_set_hw_break(unsigned long, int, enum gdb_bptype);
int gdb_remove_hw_break(unsigned long, int, enum gdb_bptype);
/*struct gdb_arch - Describe architecture specific values.*/
struct gdb_arch arch_gdb_ops = {
/* Breakpoint instruction: */
.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}, //Little-Endian
.flags = RT_GDB_HAVE_HWBP,
.set_hw_breakpoint = gdb_set_hw_break,
.remove_hw_breakpoint = gdb_remove_hw_break,
.remove_all_hw_break = gdb_remove_all_hw_break
};
static struct hw_breakpoint {
int enabled;
unsigned long addr;
} breakinfo[HBP_NUM];
static struct hw_watchpoint {
int enabled;
unsigned long addr;
int len;
enum gdb_bptype type;
} watchinfo[HWP_NUM];
//The following table defines the memory areas that GDB is allow to touch
static const struct {
unsigned long start;
unsigned long end;
} data_access[] =
{
{ 0x20000000, 0x40000000-1}, // On-chip ram
{ 0x60000000, 0xa0000000-1}, // External ram
{ 0x00000000, 0x20000000-1}, // On-chip flash
{ 0x60000000, 0xa0000000-1}, // External flash
{ 0xE0000000, 0x00000000-1}, // cortex-M peripheral
{ 0x40000000, 0x60000000-1}, // mcu peripheral
};
int gdb_permit_data_access(unsigned long addr, unsigned long count)
{
unsigned char i;
for (i = 0; i < sizeof(data_access)/sizeof(data_access[0]); i++) {
if ((addr >= data_access[i].start) && (addr + count) <= data_access[i].end) {
return 0;
}
}
return -1;
}
/*we need to block all pending interrupts by swtting basepri
* before doing the steo
*/
void gdb_single_step()
{
volatile unsigned long *base;
//mask all interrupts
single_step_basepri = regs->basepri;
regs->basepri = GDB_CORTEXM_PRIORITY_MAX;
//When MON_EN = 1, this steps the core
base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
*base |= GDB_DEBUG_REG_DEMCR_MON_STEP;
/* Clear any bits set in DFSR*/
base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
*base = 0xffffffff;
}
void gdb_clear_single_step()
{
volatile unsigned long *base;
regs->basepri = single_step_basepri;
/*clear single step*/
base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
*base &= ~GDB_DEBUG_REG_DEMCR_MON_STEP;
// Clear any bits set in DFSR
base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
*base = 0xffffffff;
}
/**
* gdb_breakpoint - generate a breadk
* It is used to sync up with a debugger and stop progarm
*/
void gdb_breakpoint()
{
volatile unsigned long *base;
// Enable the FPB-FLASH PATCH BREAKPOINT
base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_CTRL);
*base |= GDB_FPB_REG_CTRL_KEY | GDB_FPB_REG_CTRL_ENABLE ;
base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
/*
* Enable the debug monitor. When enabled, the System handler priority
* register controls its priority level.
* If disabled, then all debug events go
* to Hard fault
*/
*base |= GDB_DEBUG_REG_DEMCR_MON_EN;
// Enable DWT
*base |= GDB_DEBUG_REG_DEMCR_TRCENA ;
//Fall into debug monitor
*base |= GDB_DEBUG_REG_DEMCR_MON_PEND;
}
void gdb_set_register(void *hw_regs)
{
regs = hw_regs;
}
void gdb_get_register(unsigned long *gdb_regs)
{
int regno;
/* Initialize all to zero. */
for (regno = 0; regno < GDB_MAX_REGS; regno++)
gdb_regs[regno] = 0;
gdb_regs[GDB_R0] = regs->r0;
gdb_regs[GDB_R1] = regs->r1;
gdb_regs[GDB_R2] = regs->r2;
gdb_regs[GDB_R3] = regs->r3;
gdb_regs[GDB_R4] = regs->r4;
gdb_regs[GDB_R5] = regs->r5;
gdb_regs[GDB_R6] = regs->r6;
gdb_regs[GDB_R7] = regs->r7;
gdb_regs[GDB_R8] = regs->r8;
gdb_regs[GDB_R9] = regs->r9;
gdb_regs[GDB_R10] = regs->r10;
gdb_regs[GDB_FP] = regs->r11;
gdb_regs[GDB_IP] = regs->r12;
gdb_regs[GDB_SPT] = regs->sp;
gdb_regs[GDB_LR] = regs->lr;
gdb_regs[GDB_PC] = regs->pc;
gdb_regs[GDB_CPSR] = regs->psr;
};
void gdb_put_register(unsigned long *gdb_regs)
{
regs->r0 = gdb_regs[GDB_R0];
regs->r1 = gdb_regs[GDB_R1];
regs->r2 = gdb_regs[GDB_R2];
regs->r3 = gdb_regs[GDB_R3];
regs->r4 = gdb_regs[GDB_R4];
regs->r5 = gdb_regs[GDB_R5];
regs->r6 = gdb_regs[GDB_R6];
regs->r7 = gdb_regs[GDB_R7];
regs->r8 = gdb_regs[GDB_R8];
regs->r9 = gdb_regs[GDB_R9];
regs->r10 = gdb_regs[GDB_R10];
regs->r11 = gdb_regs[GDB_FP];
regs->r12 = gdb_regs[GDB_IP];
regs->sp = gdb_regs[GDB_SPT];
regs->lr = gdb_regs[GDB_LR];
regs->pc = gdb_regs[GDB_PC];
regs->psr = gdb_regs[GDB_CPSR];
}
/* It will be called during process_packet */
int gdb_arch_handle_exception(char *remcom_in_buffer,
char *remcom_out_buffer)
{
unsigned long addr;
char *ptr;
static int step = 0;
if (step){
gdb_clear_single_step();
step = 0;
}
switch (remcom_in_buffer[0]) {
case 'D':
case 'k':
case 'c':
/*
* If this was a compiled breakpoint, we need to move
* to the next instruction or we will breakpoint
* over and over again
*/
ptr = &remcom_in_buffer[1];
if (gdb_hex2long(&ptr, &addr))
regs->pc = addr;
return 0;
case 's':
ptr = &remcom_in_buffer[1];
if (gdb_hex2long(&ptr, &addr))
regs->pc = addr;
gdb_single_step();
step = 1;
return 0;
}
return -1;
}
int gdb_set_hw_break(unsigned long addr, int len, enum gdb_bptype bptype)
{
int i;
if (bptype == BP_HARDWARE_BREAKPOINT) {
for (i = 0; i < HBP_NUM; i++)
if (!breakinfo[i].enabled)
break;
if (i == HBP_NUM)
return -1;
breakinfo[i].addr = addr;
breakinfo[i].enabled = 1;
}
else if (bptype == BP_WRITE_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (!watchinfo[i].enabled)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].addr = addr;
watchinfo[i].len = len;
watchinfo[i].type = BP_WRITE_WATCHPOINT;
watchinfo[i].enabled = 1;
}
else if (bptype == BP_READ_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (!watchinfo[i].enabled)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].addr = addr;
watchinfo[i].len = len;
watchinfo[i].type = BP_READ_WATCHPOINT;
watchinfo[i].enabled = 1;
}
else if (bptype == BP_ACCESS_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (!watchinfo[i].enabled)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].addr = addr;
watchinfo[i].len = len;
watchinfo[i].type = BP_ACCESS_WATCHPOINT;
watchinfo[i].enabled = 1;
}
return 0;
}
int gdb_remove_hw_break(unsigned long addr, int len, enum gdb_bptype bptype)
{
int i;
if (bptype == BP_HARDWARE_BREAKPOINT) {
for (i = 0; i < HBP_NUM; i++)
if (breakinfo[i].addr == addr && breakinfo[i].enabled)
break;
if (i == HBP_NUM)
return -1;
breakinfo[i].enabled = 0;
}
else if (bptype == BP_WRITE_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].enabled = 0;
}
else if (bptype == BP_READ_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].enabled = 0;
}
else if (bptype == BP_ACCESS_WATCHPOINT) {
for (i = 0; i < HWP_NUM; i++)
if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
break;
if (i == HWP_NUM)
return -1;
watchinfo[i].enabled = 0;
}
return 0;
}
void gdb_remove_all_hw_break()
{
int i;
volatile unsigned long *base;
// Disable hardware break
for (i = 0; i < HBP_NUM; i++) {
if (!breakinfo[i].enabled)
break;
base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4);
*base &= ~GDB_FPB_REG_COMP_ENABLE ;
}
// Disable watchpoint
for (i = 0; i < HWP_NUM; i++) {
if (!watchinfo[i].enabled)
break;
base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12);
*base &= ~GDB_DWT_REG_FUNCTION_FUC ;
}
}
void gdb_arch_late()
{
gdb_remove_all_hw_break();
}
void gdb_arch_exit()
{
volatile unsigned long *base;
char num = 1;
int i;
// Install the hardware break
for (i = 0; i < HBP_NUM; i++) {
if (breakinfo[i].enabled) {
base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4);
*base = GDB_FPB_REG_COMP_ADDR & ((unsigned long)(breakinfo[i].addr));
if (breakinfo[i].addr & 2)
*base |= (1UL << 31); //set BKPT on upper halfword
else
*base |= (1UL << 30); //set BKPT on lower halfword,
*base |= GDB_FPB_REG_COMP_ENABLE ;
}
}
// Install the watchpoint
for (i = 0; i < HWP_NUM; i++) {
if (watchinfo[i].enabled) {
base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_COMP + i * 12);
*base = watchinfo[i].addr;
base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_MASK + i * 12);
while (watchinfo[i].len >> num) {
num++;
}
*base = num - 1; //DWT matching is performed as:(ADDR & (~0 << MASK)) == COMP
base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12);
if (watchinfo[i].type == BP_WRITE_WATCHPOINT)
*base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x05;
else if (watchinfo[i].type == BP_READ_WATCHPOINT)
*base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x06;
else if (watchinfo[i].type == BP_ACCESS_WATCHPOINT)
*base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x07;
}
}
}
.cpu cortex-m4
.syntax unified
.thumb
.text
.global DebugMon_Handler
.type DebugMon_Handler, %function
DebugMon_Handler:
mrs r0,psp ;// Get process stack
sub r1,r0,#(4*13) ;// Make space for saved state
msr psp,r1 ;// Ensure PSP is up to date
mov r12,r0 ;// R12 = stack
mov r1,#1 ;// R1 = exception state type
mrs r2,ipsr ;// R2 = vector number
mrs r3,basepri ;// R3 = basepri
stmfd r0!,{r1-r12,lr} ;// Push type, vector, basepri, r4-11
mov r4,r0 ;// R4 = saved state pointer
bl rt_hw_debugmon_exception
mov r0,r4 ;// R4 = saved state pointer
ldmfd r0!,{r1-r12,lr} ;// Pop type, vec, basepri, registers and LR
msr psp,r0 ;// Restore PSP
msr basepri,r3 ;// Restore basepri
bx lr ;// Return
#include <rtthread.h>
#include <gdb_stub.h>
void rt_hw_debugmon_exception(void *regs)
{
#ifdef RT_USING_GDB
gdb_arch_late();
gdb_handle_exception(SIGTRAP, regs);
gdb_arch_exit();
#endif
}
说明:
一 当前版本进度
1).分类
考虑到arm各种版本的调试寄存器地址和种类都有很大不同
所以分为两个版本,均只在GCC下编译
1.基础ARM(软件断点(使用undef指令的办法),需要ram运行,模拟单步)
2.cortex M系列(不支持M0,基于寄存器操作,支持硬件断点,数据观察点,硬件单步)
理论上cortexA系列和cortexM的调式单元是一样的,有需要的话也可以在基础arm版本里单独为cortexA做出可选的数据断点,硬件单步
二 安装说明
1) 下载
下载最新RT-THREAD GDB STUB代码,并解压
2) 加入RT-Thread
先将得到的components文件夹覆盖RTT根目录
然后若要使用BBB板测试GDB,就用BSP/beaglebone和libpcu/am335x覆盖RTT下的同名文件夹
若要使用STM32F407测试GDB,就用BSP/stm32F4xx覆盖RTT下的同名文件夹,同时更改编译器为gcc
3) 宏
打开RT_USING_GDB
三 宏配置说明
1) RT_GDB_HAVE_HWBP
1硬件断点
2) RT_GDB_HAVE_SWBP
1软件断点
3) RT_GDB_MAX_BREAKPOINTS
最大软件断点数量
不加默认20
4) RT_GDB_ICACHE
是否使用ICACHE
若使用了ICACHE则要开启此宏,保证断点覆盖后及时刷新
5) RT_GDB_DEBUG
测试开发用
会打印GDB收发信息到默认串口上,以供获取数据
四 使用说明
1) 设置serial设备
首先需要调用
void gdb_set_device(const char* device_name); (gdb_stub.h)
设置相应的GDB通信端口
PS:
首先serial的驱动不能是中断
其次收发函数最好是poll的,要不就是9600,不然可能会出现问题
若出现问题,请打开 RT_GDB_DEBUG ,观察收发是否正常。
2) 进入GDB stub
调用
void gdb_start(); (gdb_stub.h)
触发异常,即可进入等待状态 等待GDB连接
也可以将该函数加入按键中断中,可以实现外部打断程序的效果(条件有限,未测试)
3) pc连接
确认GCC 打开-g选项后编译
然后arm-none-eabi-gdb xxxx.elf or axf
进如GDB界面后
set serial baud 115200(or 9600)
target remote /dev/ttyUSB0(linux) or COM1 (windows)
即可实现GDB对接
PS:
BBB板默认uart4作为GDB通信口
STM32F407默认uart6作GDB通信
五 移植说明
若要移植到不同架构上
软件实现请参考gdb/libcpu/arm下的文件
硬件实现请参考gdb/libcpu/cortexm下的文件
需要rsp协议的话 请参考https://www.sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html
若要移植到已有架构的芯片上
1) arm9,11以及cortexA
修改udef和dabt的函数,在/libcpu/arm/am335x/trap.c里,加入ifdef GDB的内容
将libcpu/arm/am335x/start_gcc.s的相关异常向量汇编复制到自己的undef和dabt异常向量里
分配足够的栈空间给undef
2) cortexM3以及M4
删除已有的debugmon_handler
优先级分组有变化的话,重定义宏GDB_CORTEXM_PRIORITY_MAX,就是basepri的设置值,满足屏蔽中断的同时不屏蔽debugmon
使用有需要的话,重定义cortexm_stub.c的data_acess数组,也就是允许GDB访问的地址空间
增大_system_stack_size,也就是MSP栈的大小
六 易错或者bug(出错了看这里)
编译器选项是否打开-g,是否使用GCC编译
硬件断点使用超过(max-1)个后,单步可能会出现不正常
检查串口通信是否正常,可以打开RT_GDB_DEBUG
堆栈大小是否设置合适(因为gdb要在handler模式下运行,所需要的栈大小比较大,大概0x200)
cm系列切记如果优先级分组不同于默认设置,就要重定义宏GDB_CORTEXM_PRIORITY_MAX,使抢占优先级等于1,不然单步可能会出现问题(被中断抢占)
cm系列在中断里设置断点会出现错误(目测程序还是正常工作,就是压栈的寄存器还是进入中断前的,所以返回的寄存器信息有误)
cm系列可能会因为访问不可访问的地址造成出错,有需求自己手动修改cortexm_stub.c的data_acess数组(没找到好的办法,falut后寄存器全乱了)
##
嫌速度慢的话就把串口速度9600改成115200
不过如此就要把注册的驱动里的getc改成阻塞的,不然会收不到
类似
while(!(UART_LSR_REG(uart->base) & 0x01));
ch = UART_RHR_REG(uart->base) & 0xff;
原先是
if (UART_LSR_REG(uart->base) & 0x01)
{
ch = UART_RHR_REG(uart->base) & 0xff;
}
......@@ -35,11 +35,11 @@ int libc_system_init(void)
libc_stdio_set_console(dev_console->parent.name, O_WRONLY);
#endif
}
#endif
/* set PATH and HOME */
putenv("PATH=/bin");
putenv("HOME=/home");
#endif
#if defined RT_USING_PTHREADS && !defined RT_USING_COMPONENTS_INIT
pthread_system_init();
......
......@@ -44,7 +44,7 @@
*
* rti_end --> 6.end
*
* These automatically initializaiton, the driver or component initial function must
* These automatically initialization, the driver or component initial function must
* be defined with:
* INIT_BOARD_EXPORT(fn);
* INIT_DEVICE_EXPORT(fn);
......@@ -109,7 +109,7 @@ void rt_components_init(void)
int result;
const struct rt_init_desc *desc;
rt_kprintf("do components intialization.\n");
rt_kprintf("do components initialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
......@@ -215,7 +215,7 @@ int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initalization
/* board level initialization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册