cpukit: Add libdebugger, a remote debugger agent for GDB.

This commit is contained in:
Chris Johns
2016-11-25 15:13:36 +11:00
parent 8fd465e67e
commit a0d4e9933c
30 changed files with 6991 additions and 0 deletions

View File

@@ -18,6 +18,7 @@ SUBDIRS += libmd
SUBDIRS += libgnat SUBDIRS += libgnat
SUBDIRS += libdl SUBDIRS += libdl
SUBDIRS += libstdthreads SUBDIRS += libstdthreads
SUBDIRS += libdebugger
SUBDIRS += wrapup SUBDIRS += wrapup
SUBDIRS += zlib SUBDIRS += zlib
@@ -99,6 +100,14 @@ include_rtems_rtl_HEADERS += libdl/rtl-indirect-ptr.h libdl/rtl-sym.h libdl/rtl-
include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h include_rtems_rtl_HEADERS += libdl/rap.h libdl/rap-shell.h
endif endif
if LIBDEBUGGER
include_rtems_HEADERS += libdebugger/rtems-debugger.h
include_rtems_debuggerdir = $(includedir)/rtems/debugger
include_rtems_debugger_HEADERS =
include_rtems_debugger_HEADERS += libdebugger/rtems-debugger-server.h
include_rtems_debugger_HEADERS += libdebugger/rtems-debugger-remote.h
endif
include_rtems_HEADERS += include/rtems/bspIo.h include_rtems_HEADERS += include/rtems/bspIo.h
include_rtems_HEADERS += include/rtems/print.h include_rtems_HEADERS += include/rtems/print.h
include_rtems_HEADERS += include/rtems/printer.h include_rtems_HEADERS += include/rtems/printer.h

View File

@@ -396,6 +396,17 @@ esac
AM_CONDITIONAL(LIBDL,[test x"$HAVE_LIBDL" = x"yes"]) AM_CONDITIONAL(LIBDL,[test x"$HAVE_LIBDL" = x"yes"])
AC_MSG_RESULT([$HAVE_LIBDL]) AC_MSG_RESULT([$HAVE_LIBDL])
# Filter debugger to only build for architectures that have a target backend
AC_MSG_CHECKING([whether CPU supports libdebugger])
case $RTEMS_CPU in
arm | i386)
HAVE_LIBDEBUGGER=yes ;;
*)
HAVE_LIBDEBUGGER=no ;;
esac
AM_CONDITIONAL(LIBDEBUGGER,[test x"$HAVE_LIBDEBUGGER" = x"yes"])
AC_MSG_RESULT([$HAVE_LIBDEBUGGER])
AC_MSG_CHECKING([whether CPU supports SHA]) AC_MSG_CHECKING([whether CPU supports SHA])
case $RTEMS_CPU in case $RTEMS_CPU in
m32c) m32c)
@@ -474,6 +485,7 @@ libi2c/Makefile
libmd/Makefile libmd/Makefile
libdl/Makefile libdl/Makefile
libstdthreads/Makefile libstdthreads/Makefile
libdebugger/Makefile
zlib/Makefile zlib/Makefile
ftpd/Makefile ftpd/Makefile
telnetd/Makefile telnetd/Makefile

View File

@@ -0,0 +1,23 @@
if LIBDEBUGGER
include $(top_srcdir)/automake/compile.am
noinst_LIBRARIES = libdebugger.a
libdebugger_a_SOURCES = \
rtems-debugger-block.c \
rtems-debugger-cmd.c \
rtems-debugger-remote.c \
rtems-debugger-server.c \
rtems-debugger-target.c \
rtems-debugger-threads.c \
rtems-debugger-@RTEMS_CPU@.c
if LIBNETWORKING
libdebugger_a_SOURCES += \
rtems-debugger-remote-tcp.c
endif
endif
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am

View File

@@ -0,0 +1,9 @@
## Automatically generated by ampolish3 - Do not edit
if AMPOLISH3
$(srcdir)/preinstall.am: Makefile.am
$(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am
endif
if LIBDEBUGGER
endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include "rtems-debugger-block.h"
int
rtems_debugger_block_create(rtems_debugger_block* block,
size_t step,
size_t size)
{
int r = 0;
block->level = 0;
block->step = step;
block->count = step;
block->size = size;
block->block = calloc(block->count, block->size);
if (block->block == NULL)
errno = ENOMEM;
return r;
}
int
rtems_debugger_block_destroy(rtems_debugger_block* block)
{
free(block->block);
block->block = NULL;
block->level = 0;
block->count = 0;
block->size = 0;
return 0;
}
int
rtems_debugger_block_resize(rtems_debugger_block* block)
{
int r = 0;
if (block->level >= block->count) {
block->count += block->step;
block->block = realloc(block->block, block->count * block->size);
if (block->block == NULL) {
block->level = 0;
block->count = 0;
errno = ENOMEM;
r = -1;
}
}
return r;
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_BLOCK_h
#define _RTEMS_DEBUGGER_BLOCK_h
#include <rtems/rtems-debugger.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* DB server block manages a block of re-sizable memory. The block only
* grows. As more threads enter the system the block becomes the peak and then
* sits at that level.
*/
typedef struct rtems_debugger_block
{
void* block; /**< The block of memory. */
size_t step; /**< The step size the block is increased by. */
size_t size; /**< The size of the elements in the block. */
size_t count; /**< The number of elements in the block. */
size_t level; /**< The usage level in the block. */
} rtems_debugger_block;
/**
* Create a block.
*/
extern int rtems_debugger_block_create(rtems_debugger_block* block,
size_t step,
size_t size);
/**
* Destroy a block.
*/
extern int rtems_debugger_block_destroy(rtems_debugger_block* block);
/**
* Resize a block.
*/
extern int rtems_debugger_block_resize(rtems_debugger_block* block);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
#define __need_getopt_newlib
#include <getopt.h>
#include <rtems.h>
#include <rtems/printer.h>
#include <rtems/shell.h>
#include <rtems/rtems-debugger.h>
/*
* Debugger command for the RTEMS shell.
*/
static int rtems_shell_main_debugger(int argc, char *argv[])
{
if (argc == 1) {
printf("RTEMS debugger is %srunning\n", rtems_debugger_running() ? "" : "not ");
return 0;
}
if (strcasecmp(argv[1], "start") == 0) {
rtems_printer printer;
const char* remote = "tcp";
const char* device = "1122";
int timeout = RTEMS_DEBUGGER_TIMEOUT;
rtems_task_priority priority = 1;
bool verbose = false;
struct getopt_data data;
char* end;
int r;
if (rtems_debugger_running()) {
printf("error: debugger already running.\n");
return 1;
}
memset(&data, 0, sizeof(data));
rtems_print_printer_fprintf(&printer, stdout);
argv += 1;
argc -= 1;
while (true) {
int c;
c = getopt_r(argc, argv, "vR:d:t:P:l:", &data);
if (c == -1)
break;
switch (c) {
case 'v':
verbose = true;
break;
case 'R':
remote = data.optarg;
break;
case 'd':
device = data.optarg;
break;
case 't':
timeout = strtoul(data.optarg, &end, 10);
if (timeout == 0 || *end != '\0') {
printf("error: invalid timeout: %s\n", data.optarg);
return 1;
}
break;
case 'P':
priority = strtoul(data.optarg, &end, 10);
if (priority == 0 || *end != '\0') {
printf("error: invalid priority: %s\n", data.optarg);
return 1;
}
break;
case 'l':
if (strcasecmp(data.optarg, "stdout") == 0)
rtems_print_printer_fprintf(&printer, stdout);
else if (strcasecmp(data.optarg, "stderr") == 0)
rtems_print_printer_fprintf(&printer, stderr);
else if (strcasecmp(data.optarg, "kernel") == 0)
rtems_print_printer_printk(&printer);
else {
printf("error: unknown printer (stdout, stderr, kernel): %s\n", data.optarg);
return 1;
}
break;
default:
case '?':
if (data.optarg != NULL)
printf("error: unknown option: %s\n", data.optarg);
else
printf("error: invalid start command\n");
return 1;
}
}
printf("RTEMS Debugger start: remote=%s device=%s priority=%" PRIu32 "\n",
remote, device, priority);
r = rtems_debugger_start(remote, device, timeout, priority, &printer);
if (r < 0) {
printf("debugger start failed\n");
return 1;
}
rtems_debugger_set_verbose(verbose);
}
else if (strcasecmp(argv[1], "stop") == 0) {
int r;
if (!rtems_debugger_running()) {
printf("error: debugger not running.\n");
return 1;
}
r = rtems_debugger_stop();
if (r < 0) {
printf("debugger stop failed\n");
return 1;
}
}
else if (strcasecmp(argv[1], "remote-debug") == 0) {
int r;
if (!rtems_debugger_running()) {
printf("error: debugger not running.\n");
return 1;
}
if (argc == 3 && strcasecmp(argv[2], "on") == 0) {
r = rtems_debugger_remote_debug(true);
if (r < 0) {
printf("debugger remote-debug on failed\n");
return 1;
}
}
else if (argc == 3 && strcasecmp(argv[2], "off") == 0) {
r = rtems_debugger_remote_debug(false);
if (r < 0) {
printf("debugger remote-debug off failed\n");
return 1;
}
}
else {
printf("debugger remote-debug: not on or off\n");
return 1;
}
}
else if (strcasecmp(argv[1], "help") == 0) {
printf("debugger [start/stop/help] ...\n" \
" start -v -R remote -d device -t secs -P priority -l [stdout,stderr,kernel]\n" \
" stop\n" \
" remote-debug <on/off>\n" \
" help\n");
}
else {
printf("error: unknown command: %s\n", argv[1]);
return 1;
}
return 0;
}
rtems_shell_cmd_t rtems_shell_DEBUGGER_Command = {
"debugger", /* name */
"debugger [start/stop] [options ...]", /* usage */
"misc", /* topic */
rtems_shell_main_debugger, /* command */
NULL, /* alias */
NULL, /* next */
0755,
0,
0
};

View File

@@ -0,0 +1,421 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define TARGET_DEBUG 1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <rtems.h>
#include <rtems/score/threadimpl.h>
#include "rtems-debugger-target.h"
#include "rtems-debugger-threads.h"
/*
* Hardware breakpoints. Limited by hardware
*/
#define RTEMS_DEBUGGER_HWBREAK_NUM 4
/*
* Number of registers.
*/
#define RTEMS_DEBUGGER_NUMREGS 16
/*
* Number of bytes per register.
*/
#define RTEMS_DEBUGGER_REGBYTES 4
/*
* Number of bytes of registers.
*/
#define RTEMS_DEBUGGER_NUMREGBYTES \
(RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
/*
* Debugger registers layout.
*/
#define REG_EAX 0
#define REG_ECX 1
#define REG_EDX 2
#define REG_EBX 3
#define REG_ESP 4
#define REG_EBP 5
#define REG_ESI 6
#define REG_EDI 7
#define REG_PC 8
#define REG_EIP REG_PC
#define REG_PS 9
#define REG_EFLAGS REG_PS
#define REG_CS 10
#define REG_SS 11
#define REG_DS 12
#define REG_ES 13
#define REG_FS 14
#define REG_GS 15
/**
* The int 3 opcode.
*/
#define TARGET_BKPT 0xcc
static const uint8_t breakpoint[1] = { TARGET_BKPT };
/*
* Get a copy of a register.
*/
#define GET_REG(_r, _v) asm volatile("pushl %%" #_r "; popl %0" : "=rm" (_v))
/*
* Get a copy of a segment register.
*/
#define GET_SEG_REG(_r, _v) \
do { \
int _i; \
GET_REG(_r, _i); \
_v = _i & 0xffff; \
} while (0)
/**
* Target lock.
*/
RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
/**
* The orginal exception handler.
*/
static void (*orig_currentExcHandler)(CPU_Exception_frame* frame);
#if TARGET_DEBUG
#include <rtems/bspIo.h>
static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
static void
target_printk(const char* format, ...)
{
va_list ap;
va_start(ap, format);
vprintk(format, ap);
va_end(ap);
}
#else
#define target_printk(_fmt, ...)
#endif
#if TODO
/**
* Target description.
*/
static const char* const target_xml =
"<?xml version=\"1.0\"> \
<!DOCTYPE target SYSTEM \"gdb-target.dtd\"> \
<target version=\"1.0\"> \
<architecture>i386</architecture> \
<xi:include href=\"32bit-core.xml\"/> \
<xi:include href=\"32bit-sse.xml\"/> \
</target>";
#endif
int
rtems_debugger_target_configure(rtems_debugger_target* target)
{
target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
target->reg_num = RTEMS_DEBUGGER_NUMREGS;
target->reg_size = sizeof(uint32_t);
target->breakpoint = &breakpoint[0];
target->breakpoint_size = sizeof(breakpoint);
return 0;
}
static void
target_exception(CPU_Exception_frame* frame)
{
target_printk("[} frame = %08lx sig=%d (%lx)\n",
(uint32_t) frame,
rtems_debugger_target_exception_to_signal(frame),
frame->idtIndex);
target_printk("[} EAX = %" PRIx32 " EBX = %" PRIx32 \
" ECX = %" PRIx32 " EDX = %" PRIx32 "\n",
frame->eax, frame->ebx, frame->ecx, frame->edx);
target_printk("[} ESI = %" PRIx32 " EDI = %" PRIx32 \
" EBP = %" PRIx32 " ESP = %" PRIx32 "\n",
frame->esi, frame->edi, frame->ebp, frame->esp0);
target_printk("[} EIP = %" PRIx32"\n", frame->eip);
frame->eflags &= ~EFLAGS_TRAP;
switch (rtems_debugger_target_exception(frame)) {
case rtems_debugger_target_exc_consumed:
default:
break;
case rtems_debugger_target_exc_step:
frame->eflags |= EFLAGS_TRAP;
break;
case rtems_debugger_target_exc_cascade:
orig_currentExcHandler(frame);
break;
}
}
int
rtems_debugger_target_enable(void)
{
rtems_interrupt_lock_context lock_context;
rtems_interrupt_lock_acquire(&target_lock, &lock_context);
if (orig_currentExcHandler == NULL) {
orig_currentExcHandler = _currentExcHandler;
_currentExcHandler = target_exception;
}
rtems_interrupt_lock_release(&target_lock, &lock_context);
return 0;
}
int
rtems_debugger_target_disable(void)
{
rtems_interrupt_lock_context lock_context;
rtems_interrupt_lock_acquire(&target_lock, &lock_context);
if (orig_currentExcHandler != NULL)
_currentExcHandler = orig_currentExcHandler;
rtems_interrupt_lock_release(&target_lock, &lock_context);
return 0;
}
int
rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
{
if (!rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
uint32_t* regs = &thread->registers[0];
size_t i;
for (i = 0; i < rtems_debugger_target_reg_num(); ++i)
regs[i] = 0xdeaddead;
if (thread->frame) {
CPU_Exception_frame* frame = thread->frame;
regs[REG_EAX] = frame->eax;
regs[REG_ECX] = frame->ecx;
regs[REG_EDX] = frame->edx;
regs[REG_EBX] = frame->ebx;
regs[REG_ESP] = frame->esp0;
regs[REG_EBP] = frame->ebp;
regs[REG_ESI] = frame->esi;
regs[REG_EDI] = frame->edi;
regs[REG_EIP] = frame->eip;
regs[REG_EFLAGS] = frame->eflags;
regs[REG_CS] = frame->cs;
/*
* Get the signal from the frame.
*/
thread->signal = rtems_debugger_target_exception_to_signal(frame);
}
else {
regs[REG_EBX] = thread->tcb->Registers.ebx;
regs[REG_ESI] = thread->tcb->Registers.esi;
regs[REG_EDI] = thread->tcb->Registers.edi;
regs[REG_EFLAGS] = thread->tcb->Registers.eflags;
regs[REG_ESP] = (intptr_t) thread->tcb->Registers.esp;
regs[REG_EBP] = (intptr_t) thread->tcb->Registers.ebp;
regs[REG_EIP] = *((DB_UINT*) thread->tcb->Registers.esp);
regs[REG_EAX] = (intptr_t) thread;
GET_SEG_REG(CS, regs[REG_CS]);
/*
* Blocked threads have no signal.
*/
thread->signal = 0;
}
GET_SEG_REG(SS, regs[REG_SS]);
GET_SEG_REG(DS, regs[REG_DS]);
GET_SEG_REG(ES, regs[REG_ES]);
GET_SEG_REG(FS, regs[REG_FS]);
GET_SEG_REG(GS, regs[REG_GS]);
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
}
return 0;
}
int
rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
{
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
uint32_t* regs = &thread->registers[0];
/*
* Only write to debugger controlled threads. Do not touch the registers
* for threads blocked in the context switcher.
*/
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
CPU_Exception_frame* frame = thread->frame;
frame->eax = regs[REG_EAX];
frame->ecx = regs[REG_ECX];
frame->edx = regs[REG_EDX];
frame->ebx = regs[REG_EBX];
frame->esp0 = regs[REG_ESP];
frame->ebp = regs[REG_EBP];
frame->esi = regs[REG_ESI];
frame->edi = regs[REG_EDI];
frame->eip = regs[REG_EIP];
frame->eflags = regs[REG_EFLAGS];
frame->cs = regs[REG_CS];
}
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
}
return 0;
}
DB_UINT
rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
{
int r;
r = rtems_debugger_target_read_regs(thread);
if (r >= 0) {
uint32_t* regs = &thread->registers[0];
return regs[REG_EIP];
}
return 0;
}
DB_UINT
rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
{
return (DB_UINT) frame->eip;
}
DB_UINT
rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
{
int r;
r = rtems_debugger_target_read_regs(thread);
if (r >= 0) {
uint32_t* regs = &thread->registers[0];
return regs[REG_ESP];
}
return 0;
}
DB_UINT
rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
{
return (DB_UINT) thread->tcb->Registers.esp;
}
int
rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
{
if (rtems_debugger_thread_flag(thread,
(RTEMS_DEBUGGER_THREAD_FLAG_STEP |
RTEMS_DEBUGGER_THREAD_FLAG_STEPPING))) {
CPU_Exception_frame* frame = thread->frame;
/*
* Single step instructions with interrupts masked to avoid stepping into
* an interrupt handler.
*/
if ((frame->eflags & EFLAGS_INTR_ENABLE) == 0)
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
else
frame->eflags &= ~EFLAGS_INTR_ENABLE;
frame->eflags |= EFLAGS_TRAP;
}
return 0;
}
int
rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
{
int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
switch (frame->idtIndex) {
case 1: /* debug exception */
case 3: /* breakpoint int3 */
sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
break;
case 4: /* int overflow */
case 5: /* out-of-bounds */
sig = RTEMS_DEBUGGER_SIGNAL_URG;
break;
case 6: /* invalid opcode */
sig = RTEMS_DEBUGGER_SIGNAL_ILL;
break;
case 8: /* double fault */
case 16: /* fp error */
sig = RTEMS_DEBUGGER_SIGNAL_EMT;
break;
case 0: /* divide by zero */
case 7: /* FPU not avail. */
sig = RTEMS_DEBUGGER_SIGNAL_FPE;
break;
case 9: /* i387 seg overr. */
case 10: /* Invalid TSS */
case 11: /* seg. not pres. */
case 12: /* stack except. */
case 13: /* general prot. */
case 14: /* page fault */
case 17: /* alignment check */
sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
break;
case 2: /* NMI */
case 18: /* machine check */
sig = RTEMS_DEBUGGER_SIGNAL_BUS;
break;
default:
break;
}
return sig;
}
int
rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
bool insert,
DB_UINT addr,
DB_UINT kind)
{
/*
* To do.
*/
return 0;
}
int
rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
{
/*
* Nothing to do on an i386.
*/
return 0;
}

View File

@@ -0,0 +1,342 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <rtems/rtems-debugger.h>
#include <rtems/debugger/rtems-debugger-server.h>
#include <rtems/debugger/rtems-debugger-remote.h>
#include "rtems-debugger-remote-tcp.h"
/**
* Debugger default server port. 'RT' as ASCII.
*/
#define RTEMS_DB_PORT_DEFAULT (8284)
/**
* TCP Remote data.
*/
typedef struct
{
int fd;
int port;
} rtems_debugger_remote_tcp;
static rtems_debugger_remote_tcp*
tcp_remote(rtems_debugger_remote* remote)
{
rtems_debugger_remote_tcp* tcp = NULL;
rtems_debugger_lock();
if (remote != NULL && remote->data != NULL)
tcp = (rtems_debugger_remote_tcp*) remote->data;
rtems_debugger_unlock();
return tcp;
}
static int
tcp_remote_begin(rtems_debugger_remote* remote, const char* device)
{
rtems_debugger_remote_tcp* tcp;
int port;
char* end;
rtems_debugger_lock();
/*
* Parse the port number.
*/
port = strtoul(device, &end, 10);
if (port == 0 || *end != '\0') {
rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device);
return -1;
}
tcp = malloc(sizeof(rtems_debugger_remote_tcp));
if (tcp == NULL) {
errno = ENOMEM;
return -1;
}
remote->data = tcp;
tcp->fd = -1;
tcp->port = port;
rtems_debugger_unlock();
return 0;
}
static int
tcp_remote_end(rtems_debugger_remote* remote)
{
rtems_debugger_lock();
if (remote != NULL && remote->data != NULL) {
rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data;
if (tcp != NULL) {
if (tcp->fd >= 0)
close(tcp->fd);
free(tcp);
remote->data = NULL;
}
}
rtems_debugger_unlock();
return 0;
}
static int
tcp_remote_connect(rtems_debugger_remote* remote)
{
int ld;
struct sockaddr_in addr;
socklen_t opt;
socklen_t len;
bool running;
struct timeval timeout;
rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
int r;
if (rtems_debugger_verbose())
rtems_debugger_printf("error: rtems-db: tcp remote: connect\n");
ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ld < 0) {
rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n",
errno, strerror(errno));
return -1;
}
opt = 1;
r = setsockopt(ld,
SOL_SOCKET,
SO_REUSEADDR,
(char *) &opt,
sizeof(opt));
if (r < 0) {
close(ld);
rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n",
errno, strerror(errno));
return -1;
}
addr.sin_family = PF_INET;
addr.sin_port = htons(tcp->port);
addr.sin_addr.s_addr = INADDR_ANY;
r = bind(ld, (struct sockaddr *) &addr, sizeof(addr));
if (r < 0) {
close(ld);
rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n",
errno, strerror(errno));
return -1;
}
/*
* Backlog of 1 connection.
*/
r = listen(ld, 1);
if (r < 0) {
close(ld);
rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n",
errno, strerror(errno));
return -1;
}
/*
* Use a random port if the port is 0.
*/
if (tcp->port == 0) {
len = sizeof(addr);
r = getsockname(ld, (struct sockaddr *) &addr, &len);
if (r < 0 || len < sizeof(addr)) {
close(ld);
rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n",
errno, strerror(errno));
return -1;
}
tcp->port = ntohs(addr.sin_port);
}
rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n",
tcp->port);
len = sizeof(addr);
tcp->fd = accept(ld, (struct sockaddr *) &addr, &len);
running = rtems_debugger_server_running();
close(ld);
if (tcp->fd < 0) {
/*
* EBADF means the socket has been closed, ignore it.
*/
if (errno != EBADF)
rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n",
errno, strerror(errno));
return -1;
}
if (!running) {
close(tcp->fd);
errno = EIO;
return -1;
}
opt = 1;
r = setsockopt(tcp->fd,
SOL_SOCKET, SO_KEEPALIVE,
(char*) &opt,
sizeof(opt));
if (r < 0) {
int errno_ = errno;
close(tcp->fd);
rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n",
errno, strerror(errno));
errno = errno_;
return -1;
}
opt = 1;
r = setsockopt(tcp->fd,
IPPROTO_TCP, TCP_NODELAY,
(char*) &opt, sizeof(opt));
if (r < 0) {
int errno_ = errno;
close(tcp->fd);
rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n",
errno, strerror(errno));
errno = errno_;
return -1;
}
timeout.tv_sec = rtems_debugger->timeout;
timeout.tv_usec = 0;
r = setsockopt(tcp->fd,
SOL_SOCKET, SO_RCVTIMEO,
(char*) &timeout, sizeof(timeout));
if (r < 0) {
int errno_ = errno;
close(tcp->fd);
rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n",
errno, strerror(errno));
errno = errno_;
return -1;
}
rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n",
inet_ntoa(addr.sin_addr));
return 0;
}
static int
tcp_remote_disconnect(rtems_debugger_remote* remote)
{
rtems_debugger_remote_tcp* tcp;
rtems_debugger_lock();
rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n");
tcp = (rtems_debugger_remote_tcp*) remote->data;
close(tcp->fd);
rtems_debugger_unlock();
return 0;
}
static bool
tcp_remote_isconnected(rtems_debugger_remote* remote)
{
rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
return tcp != NULL && tcp->fd >= 0;
}
static ssize_t
tcp_remote_receive(rtems_debugger_remote* remote,
void* buf,
size_t nbytes)
{
rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
ssize_t len;
if (tcp != NULL) {
len = read(tcp->fd, buf, nbytes);
}
else {
errno = EIO;
len = -1;
}
return len;
}
static ssize_t
tcp_remote_send(rtems_debugger_remote* remote,
const void* buf,
size_t nbytes)
{
rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
ssize_t len;
if (tcp != NULL) {
len = write(tcp->fd, buf, nbytes);
}
else {
errno = EIO;
len = -1;
}
return len;
}
static rtems_debugger_remote remote_tcp =
{
.name = "tcp",
.begin = tcp_remote_begin,
.end = tcp_remote_end,
.connect = tcp_remote_connect,
.disconnect = tcp_remote_disconnect,
.isconnected = tcp_remote_isconnected,
.read = tcp_remote_receive,
.write = tcp_remote_send
};
int
rtems_debugger_register_tcp_remote(void)
{
return rtems_debugger_remote_register(&remote_tcp);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_REMOTE_TCP_h
#define _RTEMS_DEBUGGER_REMOTE_TCP_h
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Register a remote with the server.
*/
int rtems_debugger_register_tcp_remote(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <rtems/rtems-debugger.h>
#include <rtems/debugger/rtems-debugger-server.h>
#include <rtems/debugger/rtems-debugger-remote.h>
static rtems_debugger_remote* remotes[4];
int
rtems_debugger_remote_register(rtems_debugger_remote* remote)
{
size_t r;
if (remote->begin == NULL || remote->end == NULL ||
remote->connect == NULL || remote->disconnect == NULL ||
remote->isconnected == NULL ||
remote->read == NULL || remote->write == NULL) {
errno = EINVAL;
return -1;
}
for (r = 0; r < RTEMS_DEBUGGER_NUMOF(remotes); ++r) {
if (remotes[r] == NULL) {
remotes[r] = remote;
return 0;
}
}
errno = ENOSPC;
return -1;
}
rtems_debugger_remote*
rtems_debugger_remote_find(const char* name)
{
size_t r;
for (r = 0; r < RTEMS_DEBUGGER_NUMOF(remotes); ++r) {
if (remotes[r] != NULL) {
if (strcasecmp(name, remotes[r]->name) == 0)
return remotes[r];
}
}
return NULL;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_REMOTE_h
#define _RTEMS_DEBUGGER_REMOTE_h
#include <rtems/rtems-debugger.h>
#include <rtems/debugger/rtems-debugger-server.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Debugger remote.
*/
struct rtems_debugger_remote
{
const char* name;
int (*begin)(rtems_debugger_remote* remote, const char* device);
int (*end)(rtems_debugger_remote* remote);
int (*connect)(rtems_debugger_remote* remote);
int (*disconnect)(rtems_debugger_remote* remote);
bool (*isconnected)(rtems_debugger_remote* remote);
ssize_t (*read)(rtems_debugger_remote* remote, void* buf, size_t nbytes);
ssize_t (*write)(rtems_debugger_remote* remote, const void* buf, size_t nbytes);
void* data;
};
/**
* Register a remote with the server.
*/
int rtems_debugger_remote_register(rtems_debugger_remote* remote);
/**
* Find a remote by name.
*/
rtems_debugger_remote* rtems_debugger_remote_find(const char* name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_SERVER_h
#define _RTEMS_DEBUGGER_SERVER_h
#include <rtems.h>
#include <rtems/printer.h>
#include <rtems/rtems-debugger.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Debugger NUMOF macro.
*/
#define RTEMS_DEBUGGER_NUMOF(_d) (sizeof(_d) / sizeof(_d[0]))
/**
* Machine specific size. Here for 64bit support.
*/
#define DB_UINT uint32_t
/*
* Debugger signals.
*/
#define RTEMS_DEBUGGER_SIGNAL_HUP 1 /* Hangup */
#define RTEMS_DEBUGGER_SIGNAL_INT 2 /* Interrupt */
#define RTEMS_DEBUGGER_SIGNAL_QUIT 3 /* Quit */
#define RTEMS_DEBUGGER_SIGNAL_ILL 4 /* Illegal instruction */
#define RTEMS_DEBUGGER_SIGNAL_TRAP 5 /* Trace/breakpoint trap */
#define RTEMS_DEBUGGER_SIGNAL_ABRT 6 /* Aborted */
#define RTEMS_DEBUGGER_SIGNAL_EMT 7 /* Emulation trap */
#define RTEMS_DEBUGGER_SIGNAL_FPE 8 /* Arithmetic exception */
#define RTEMS_DEBUGGER_SIGNAL_KILL 9 /* Killed */
#define RTEMS_DEBUGGER_SIGNAL_BUS 10 /* Bus error */
#define RTEMS_DEBUGGER_SIGNAL_SEGV 11 /* Segmentation fault */
#define RTEMS_DEBUGGER_SIGNAL_SYS 12 /* Bad system call */
#define RTEMS_DEBUGGER_SIGNAL_PIPE 13 /* Broken pipe */
#define RTEMS_DEBUGGER_SIGNAL_ALRM 14 /* Alarm clock */
#define RTEMS_DEBUGGER_SIGNAL_TERM 15 /* Terminated */
#define RTEMS_DEBUGGER_SIGNAL_URG 16 /* Urgent I/O condition */
#define RTEMS_DEBUGGER_SIGNAL_STOP 17 /* Stopped (signal) */
#define RTEMS_DEBUGGER_SIGNAL_TSTP 18 /* Stopped (user) */
#define RTEMS_DEBUGGER_SIGNAL_CONT 19 /* Continued */
/**
* Timeout period for the Debugger task to stop in usecs.
*/
#define RTEMS_DEBUGGER_TIMEOUT_STOP (5 * 1000 * 1000)
/**
* Debugger poll wait timeout in usecs.
*/
#define RTEMS_DEBUGGER_POLL_WAIT (10000)
/**
* Debugger task stack size.
*/
#define RTEMS_DEBUGGER_STACKSIZE (16 * 1024)
/**
* Debugger output buffer size.
*/
#define RTEMS_DEBUGGER_BUFFER_SIZE (4 * 1024)
/**
* Debugger flags.
*/
#define RTEMS_DEBUGGER_FLAG_VERBOSE (1 << 0)
#define RTEMS_DEBUGGER_FLAG_RESET (1 << 1)
#define RTEMS_DEBUGGER_FLAG_NON_STOP (1 << 2)
#define RTEMS_DEBUGGER_FLAG_VCONT (1 << 3)
#define RTEMS_DEBUGGER_FLAG_MULTIPROCESS (1 << 4)
/**
* Forward decl for the threads and targets.
*/
typedef struct rtems_debugger_remote rtems_debugger_remote;
typedef struct rtems_debugger_threads rtems_debugger_threads;
typedef struct rtems_debugger_target rtems_debugger_target;
/**
* Debugger data.
*/
typedef struct
{
int port;
int timeout;
rtems_task_priority priority;
rtems_id lock;
rtems_id lock_output;
rtems_debugger_remote* remote;
rtems_id server_task;
volatile bool server_running;
volatile bool server_finished;
rtems_id events_task;
volatile bool events_running;
volatile bool events_finished;
rtems_printer printer;
uint32_t flags;
pid_t pid;
bool remote_debug;
bool ack_pending;
size_t output_level;
uint8_t input[RTEMS_DEBUGGER_BUFFER_SIZE];
uint8_t output[RTEMS_DEBUGGER_BUFFER_SIZE];
rtems_debugger_threads* threads;
int signal;
rtems_debugger_target* target;
} rtems_debugger_server;
/**
* Debugger global variable.
*/
extern rtems_debugger_server* rtems_debugger;
/**
* Debug server printer.
*/
extern int rtems_debugger_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
/**
* Lock the Debugger.
*/
extern int rtems_debugger_lock(void);
/**
* Unlock the Debugger.
*/
extern int rtems_debugger_unlock(void);
/**
* Is the server still running?
*/
bool rtems_debugger_server_running(void);
/**
* Get the remote handle from the debugger.
*/
rtems_debugger_remote* rtems_debugger_remote_handle(void);
/**
* Is the debugger connected?
*/
bool rtems_debugger_connected(void);
/**
* Is the debugger events thread runnins?
*/
bool rtems_debugger_server_events_running(void);
/**
* Wake events thread in the debug server.
*/
extern int rtems_debugger_server_events_wake(void);
/**
* Check if verbose is on.
*/
extern bool rtems_debugger_verbose(void);
/**
* Check a flag.
*/
static inline bool rtems_debugger_server_flag(uint32_t mask)
{
return (rtems_debugger->flags & mask) != 0;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -0,0 +1,400 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define TARGET_DEBUG 0
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <rtems.h>
#include <rtems/score/threadimpl.h>
#include "rtems-debugger-target.h"
#include "rtems-debugger-threads.h"
/**
* Frame signature.
*/
#define TARGET_FRAME_MAGIC_NUM (2)
#define TARGET_FRAME_MAGIC 0xdeadbeef, 0xb2107016
static const uint32_t
frame_magic[TARGET_FRAME_MAGIC_NUM] = { TARGET_FRAME_MAGIC };
#if TARGET_DEBUG
#include <rtems/bspIo.h>
static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
static void
target_printk(const char* format, ...)
{
va_list ap;
va_start(ap, format);
vprintk(format, ap);
va_end(ap);
}
#else
#define target_printk(_fmt, ...)
#endif
int
rtems_debugger_target_create(void)
{
if (rtems_debugger->target == NULL) {
rtems_debugger_target* target;
int r;
target = calloc(1, sizeof(rtems_debugger_target));
if (target == NULL) {
errno = ENOMEM;
return -1;
}
r = rtems_debugger_target_configure(target);
if (r < 0) {
free(target);
return -1;
}
if (target->breakpoint_size > RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE) {
free(target);
rtems_debugger_printf("error: rtems-db: target: breakpoint size too big\n");
return -1;
}
r = rtems_debugger_block_create(&target->swbreaks,
RTEMS_DEBUGGER_TARGET_SWBREAK_NUM,
sizeof(rtems_debugger_target_swbreak));
if (r < 0) {
free(target);
return -1;
}
rtems_debugger->target = target;
}
return 0;
}
int
rtems_debugger_target_destroy(void)
{
if (rtems_debugger->target != NULL) {
rtems_debugger_target* target = rtems_debugger->target;
rtems_debugger_target_swbreak_remove();
rtems_debugger_target_disable();
rtems_debugger_block_destroy(&target->swbreaks);
free(target);
rtems_debugger->target = NULL;
}
return 0;
}
uint32_t
rtems_debugger_target_capabilities(void)
{
if (rtems_debugger->target != NULL)
return rtems_debugger->target->capabilities;
return 0;
}
size_t
rtems_debugger_target_reg_num(void)
{
if (rtems_debugger->target != NULL)
return rtems_debugger->target->reg_num;
return 0;
}
size_t
rtems_debugger_target_reg_size(void)
{
if (rtems_debugger->target != NULL)
return rtems_debugger->target->reg_num * rtems_debugger->target->reg_size;
return 0;
}
int
rtems_debugger_target_swbreak_control(bool insert, DB_UINT addr, DB_UINT kind)
{
rtems_debugger_target* target = rtems_debugger->target;
rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
size_t swbreak_size;
uint8_t* loc = (void*) addr;
size_t i;
int r;
if (target == NULL || swbreaks == NULL || kind != target->breakpoint_size) {
errno = EIO;
return -1;
}
swbreak_size =
sizeof(rtems_debugger_target_swbreak) + target->breakpoint_size;
for (i = 0; i < target->swbreaks.level; ++i) {
if (loc == swbreaks[i].address) {
size_t remaining;
if (!insert) {
--target->swbreaks.level;
remaining = (target->swbreaks.level - i) * swbreak_size;
memmove(&swbreaks[i], &swbreaks[i + 1], remaining);
}
return 0;
}
}
if (!insert)
return 0;
r = rtems_debugger_block_resize(&target->swbreaks);
if (r < 0)
return -1;
swbreaks = target->swbreaks.block;
swbreaks[target->swbreaks.level].address = loc;
if (target->breakpoint_size > 4)
memcpy(&swbreaks[target->swbreaks.level].contents[0],
loc,
target->breakpoint_size);
else {
uint8_t* contents = &swbreaks[target->swbreaks.level].contents[0];
switch (target->breakpoint_size) {
case 4:
contents[3] = loc[3];
case 3:
contents[2] = loc[2];
case 2:
contents[1] = loc[1];
case 1:
contents[0] = loc[0];
break;
}
}
++target->swbreaks.level;
return 0;
}
int
rtems_debugger_target_swbreak_insert(void)
{
rtems_debugger_target* target = rtems_debugger->target;
int r = -1;
if (target != NULL && target->swbreaks.block != NULL) {
rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
size_t i;
r = 0;
for (i = 0; i < target->swbreaks.level; ++i) {
uint8_t* loc = swbreaks[i].address;
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: bp: in: %p\n", swbreaks[i].address);
if (target->breakpoint_size > 4)
memcpy(loc, &target->breakpoint[0], target->breakpoint_size);
else {
switch (target->breakpoint_size) {
case 4:
loc[3] = target->breakpoint[3];
case 3:
loc[2] = target->breakpoint[2];
case 2:
loc[1] = target->breakpoint[1];
case 1:
loc[0] = target->breakpoint[0];
break;
}
}
r = rtems_debugger_target_cache_sync(&swbreaks[i]);
}
}
return r;
}
int
rtems_debugger_target_swbreak_remove(void)
{
rtems_debugger_target* target = rtems_debugger->target;
int r = -1;
if (target != NULL && target->swbreaks.block != NULL) {
rtems_debugger_target* target = rtems_debugger->target;
rtems_debugger_target_swbreak* swbreaks = target->swbreaks.block;
size_t i;
r = 0;
for (i = 0; i < target->swbreaks.level; ++i) {
uint8_t* loc = swbreaks[i].address;
uint8_t* contents = &swbreaks[i].contents[0];
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: bp: out: %p\n", swbreaks[i].address);
if (target->breakpoint_size > 4)
memcpy(loc, contents, target->breakpoint_size);
else {
switch (target->breakpoint_size) {
case 4:
loc[3] = contents[3];
case 3:
loc[2] = contents[2];
case 2:
loc[1] = contents[1];
case 1:
loc[0] = contents[0];
break;
}
}
r = rtems_debugger_target_cache_sync(&swbreaks[i]);
}
}
return r;
}
rtems_debugger_target_exc_action
rtems_debugger_target_exception(CPU_Exception_frame* frame)
{
volatile const uint32_t magic[3] = {
(uint32_t) frame, TARGET_FRAME_MAGIC
};
(void) magic;
if (!rtems_interrupt_is_in_progress()) {
rtems_debugger_threads* threads = rtems_debugger->threads;
Thread_Control* thread = _Thread_Executing;
rtems_id* excludes;
const rtems_id tid = thread->Object.id;
DB_UINT pc;
const rtems_debugger_thread_stepper* stepper;
size_t i;
target_printk("[} tid:%08" PRIx32 ": thread:%08" PRIxPTR
" frame:%08" PRIxPTR "\n",
tid, (intptr_t) thread, (intptr_t) frame);
/*
* If the thread is the debugger recover.
*/
if (tid == rtems_debugger->server_task) {
if (rtems_debugger->target->memory_access) {
target_printk("[} server access fault\n");
rtems_debugger->target->memory_access = true;
longjmp(rtems_debugger->target->access_return, -1);
}
target_printk("[} server exception\n");
return rtems_debugger_target_exc_cascade;
}
/*
* See if the thread is excluded.
*/
excludes = rtems_debugger_thread_excludes(threads);
for (i = 0; i < threads->excludes.level; ++i) {
if (tid == excludes[i]) {
/*
* We do nothing with this condition and cascade the exception.
*
* @todo: if this is a hwbreak carry on, if this is a swbreak replace
* the contents of the instruction, step then return the
* swbreak's contents.
*/
target_printk("[} tid:%08lx: excluded\n", tid);
return rtems_debugger_target_exc_cascade;
}
}
/*
* See if the thread is inside the stepping a range.
*/
pc = rtems_debugger_target_frame_pc(frame);
stepper = rtems_debugger_thread_is_stepping(tid, pc);
if (stepper != NULL) {
stepper->thread->frame = frame;
rtems_debugger_target_thread_stepping(stepper->thread);
target_printk("[} tid:%08lx: stepping\n", tid);
return rtems_debugger_target_exc_step;
}
target_printk("[} tid:%08lx: suspending\n", tid);
/*
* Tag the thread as being debugged, wake the debug server's event thread,
* then suspend this thread.
*/
_Thread_Set_state(thread, STATES_DEBUGGER);
rtems_debugger_server_events_wake();
rtems_task_suspend(tid);
target_printk("[} tid:%08lx: resuming\n", tid);
return rtems_debugger_target_exc_consumed;
}
target_printk("[} cascade, in interrupt\n");
return rtems_debugger_target_exc_cascade;
}
int
rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread)
{
int r = 0;
thread->frame = NULL;
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING;
if ((thread->tcb->current_state & STATES_DEBUGGER) != 0) {
CPU_Exception_frame* frame = NULL;
DB_UINT* sp;
int i;
sp = (DB_UINT*) rtems_debugger_target_tcb_sp(thread);
for (i = 0; i < 128; ++i) {
if (sp[i] == frame_magic[0] && sp[i + 1] == frame_magic[1]) {
frame = (CPU_Exception_frame*) sp[i + 2];
break;
}
}
_Thread_Clear_state(thread->tcb, STATES_DEBUGGER);
thread->frame = frame;
if (frame != NULL)
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING;
else
r = -1;
}
return r;
}
int
rtems_debugger_target_start_memory_access(void)
{
rtems_debugger_target* target = rtems_debugger->target;
target->memory_access = true;
return setjmp(target->access_return);
}
void
rtems_debugger_target_end_memory_access(void)
{
rtems_debugger->target->memory_access = false;
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_TARGET_h
#define _RTEMS_DEBUGGER_TARGET_h
#include <setjmp.h>
#include <rtems/rtems-debugger.h>
#include "rtems-debugger-threads.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Software breakpoint block size.
*/
#define RTEMS_DEBUGGER_TARGET_SWBREAK_NUM 64
/**
* Target capabilities mask.
*/
#define RTEMS_DEBUGGER_TARGET_CAP_SWBREAK (1 << 0)
#define RTEMS_DEBUGGER_TARGET_CAP_HWBREAK (1 << 1)
#define RTEMS_DEBUGGER_TARGET_CAP_HWWATCH (1 << 2)
/**
* Types of hardware breakpoints.
*/
typedef enum rtems_debugger_target_watchpoint
{
rtems_debugger_target_hw_read,
rtems_debugger_target_hw_write,
rtems_debugger_target_hw_read_write,
rtems_debugger_target_hw_execute
} rtems_debugger_target_watchpoint;
/**
* Target exception actions.
*/
typedef enum rtems_debugger_target_exc_action
{
rtems_debugger_target_exc_consumed, /*<< The exception has been consumed. */
rtems_debugger_target_exc_cascade, /*<< Cascade to a previous handler. */
rtems_debugger_target_exc_step, /*<< Step an instruction. */
} rtems_debugger_target_exc_action;
/**
* Memory breakpoint. We use thumb mode BKPT which is 2 bytes.
*/
#define RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE (4)
typedef struct rtems_debugger_target_swbreak {
void* address;
uint8_t contents[RTEMS_DEBUGGER_TARGET_SWBREAK_MAX_SIZE];
} rtems_debugger_target_swbreak;
/**
* The target data.
*/
typedef struct rtems_debugger_target {
int capabilities; /*<< The capabilities to report. */
size_t reg_num; /*<< The number of registers. */
size_t reg_size; /*<< The size of a register. */
const uint8_t* breakpoint; /*<< The breakpoint instruction(s). */
size_t breakpoint_size; /*<< The breakpoint size. */
rtems_debugger_block swbreaks; /*<< The software breakpoint block. */
bool memory_access; /*<< Accessing target memory. */
jmp_buf access_return; /*<< Return from an access fault. */
} rtems_debugger_target;
/**
* Create the target.
*/
extern int rtems_debugger_target_create(void);
/**
* Destroy the target.
*/
extern int rtems_debugger_target_destroy(void);
/**
* Configure the target. This is architecture specific.
*/
extern int rtems_debugger_target_configure(rtems_debugger_target* target);
/**
* Enable the target.
*/
extern int rtems_debugger_target_enable(void);
/**
* Disable the target.
*/
extern int rtems_debugger_target_disable(void);
/**
* Return the capabilities mask for the target.
*/
extern uint32_t rtems_debugger_target_capabilities(void);
/**
* Return the number of regisers.
*/
extern size_t rtems_debugger_target_reg_num(void);
/**
* Return the size of the regisers in bytes.
*/
extern size_t rtems_debugger_target_reg_size(void);
/**
* Read the regosters.
*/
extern int rtems_debugger_target_read_regs(rtems_debugger_thread* thread);
/**
* Write the regosters.
*/
extern int rtems_debugger_target_write_regs(rtems_debugger_thread* thread);
/**
* Return the thread's program counter (PC).
*/
extern DB_UINT rtems_debugger_target_reg_pc(rtems_debugger_thread* thread);
/**
* Return the frame's program counter (PC).
*/
extern DB_UINT rtems_debugger_target_frame_pc(CPU_Exception_frame* frame);
/**
* Return the thread's stack pointer (SP).
*/
extern DB_UINT rtems_debugger_target_reg_sp(rtems_debugger_thread* thread);
/**
* Return the thread's TCB stack pointer (SP).
*/
extern DB_UINT rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread);
/**
* The thread is stepping. Setup the thread to step an instruction.
*/
extern int rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread);
/**
* Return the signal for the exception.
*/
extern int rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame);
/**
* Software breakpoints. These are also referred to as memory breakpoints.
*/
extern int rtems_debugger_target_swbreak_control(bool insert,
DB_UINT addr,
DB_UINT kind);
/**
* Insert software breakpoints into the memory.
*/
extern int rtems_debugger_target_swbreak_insert(void);
/**
* Remove software breakpoints from the memory.
*/
extern int rtems_debugger_target_swbreak_remove(void);
/**
* Hardware breakpoints.
*/
extern int rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint type,
bool insert,
DB_UINT addr,
DB_UINT kind);
/**
* Target exception processor.
*/
extern rtems_debugger_target_exc_action
rtems_debugger_target_exception(CPU_Exception_frame* frame);
/**
* Set the thread's exception stack frame pointer.
*/
extern int rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread);
/**
* Target instruction cache sync. This depends on the target but it normally
* means a data cache flush and an instruction cache invalidate.
*/
extern int rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak);
/**
* Start a target memory access. If 0 is return the access can proceed and if
* -1 is return the access has failed.
*/
extern int rtems_debugger_target_start_memory_access(void);
/**
* End a target memory access.
*/
extern void rtems_debugger_target_end_memory_access(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -0,0 +1,577 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <rtems.h>
#include <rtems/score/statesimpl.h>
#include <rtems/score/threadimpl.h>
#include <rtems/debugger/rtems-debugger-server.h>
#include "rtems-debugger-target.h"
#include "rtems-debugger-threads.h"
static const char const* excludes_defaults[] =
{
"TIME",
"_BSD",
"IRQS",
"DBSs",
"DBSe",
};
static void
rtems_debugger_thread_free(rtems_debugger_threads* threads)
{
rtems_debugger_block_destroy(&threads->current);
rtems_debugger_block_destroy(&threads->registers);
rtems_debugger_block_destroy(&threads->excludes);
rtems_debugger_block_destroy(&threads->stopped);
rtems_debugger_block_destroy(&threads->steppers);
threads->next = 0;
}
int
rtems_debugger_thread_create(void)
{
rtems_debugger_threads* threads;
int r;
threads = calloc(1, sizeof(rtems_debugger_threads));
if (threads == NULL) {
errno = ENOMEM;
rtems_debugger_printf("error: rtems-db: thread: threads alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
r = rtems_debugger_block_create(&threads->current,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
sizeof(rtems_debugger_thread));
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger_printf("error: rtems-db: thread: current alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
r = rtems_debugger_block_create(&threads->registers,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
rtems_debugger_target_reg_size());
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger_printf("error: rtems-db: thread: registers alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
r = rtems_debugger_block_create(&threads->excludes,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
sizeof(rtems_id));
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger_printf("error: rtems-db: thread: exlcudes alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
r = rtems_debugger_block_create(&threads->stopped,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
sizeof(rtems_id));
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger_printf("error: rtems-db: thread: stopped alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
r = rtems_debugger_block_create(&threads->steppers,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
sizeof(rtems_debugger_thread_stepper));
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger_printf("error: rtems-db: thread: steppers alloc: (%d) %s\n",
errno, strerror(errno));
return -1;
}
rtems_debugger->threads = threads;
return rtems_debugger_thread_system_suspend();
}
int
rtems_debugger_thread_destroy(void)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread_system_resume(true);
rtems_debugger_thread_free(threads);
free(threads);
rtems_debugger->threads = NULL;
return 0;
}
int
rtems_debugger_thread_find_index(rtems_id id)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread* current = rtems_debugger_thread_current(threads);
int r = -1;
if (threads != NULL) {
size_t i;
for (i = 0; i < threads->current.level; ++i) {
if (id == 0 || current[i].id == id) {
r = i;
break;
}
}
}
return r;
}
static bool
snapshot_thread(rtems_tcb* tcb, void* arg)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_id id = tcb->Object.id;
char name[RTEMS_DEBUGGER_THREAD_NAME_SIZE];
bool exclude = false;
size_t i;
/*
* The only time the threads pointer is NULL is a realloc error so we stop
* processing threads. There is no way to stop the iterator.
*/
if (rtems_debugger_thread_current(threads) == NULL)
return true;
/*
* Filter the threads.
*/
switch (rtems_object_id_get_api(id)) {
case OBJECTS_NO_API:
case OBJECTS_INTERNAL_API:
exclude = true;
break;
default:
rtems_object_get_name(id, sizeof(name), (char*) &name[0]);
for (i = 0; i < RTEMS_DEBUGGER_NUMOF(excludes_defaults); ++i) {
if (strcmp(excludes_defaults[i], name) == 0) {
exclude = true;
break;
}
}
break;
}
if (exclude) {
rtems_id* excludes;
int r;
r = rtems_debugger_block_resize(&threads->excludes);
if (r < 0) {
rtems_debugger_thread_free(threads);
return true;
}
excludes = rtems_debugger_thread_excludes(threads);
excludes[threads->excludes.level++] = id;
}
else {
rtems_debugger_thread* current;
DB_UINT* registers;
rtems_debugger_thread* thread;
int r;
r = rtems_debugger_block_resize(&threads->current);
if (r < 0) {
rtems_debugger_thread_free(threads);
return true;
}
r = rtems_debugger_block_resize(&threads->registers);
if (r < 0) {
rtems_debugger_thread_free(threads);
return true;
}
current = rtems_debugger_thread_current(threads);
registers = rtems_debugger_thread_registers(threads);
thread = &current[threads->current.level++];
thread->registers =
&registers[threads->registers.level++ * rtems_debugger_target_reg_num()];
thread->tcb = tcb;
thread->id = id;
thread->flags = 0;
thread->signal = 0;
thread->frame = NULL;
memcpy((void*) &thread->name[0], &name[0], sizeof(thread->name));
/*
* See if there is a valid exception stack frame and if the thread is being
* debugged.
*/
r = rtems_debugger_target_set_exception_frame(thread);
if (r < 0) {
rtems_debugger_printf("error: rtems-db: thread: snap: %08lx: not valid frame\n",
id);
}
/*
* Read the target registers into the thread register array.
*/
rtems_debugger_target_read_regs(thread);
/*
* Debugger threads are stopped for breakpoint, segv or other errors have
* the RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING set.
*/
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
rtems_id* stopped;
r = rtems_debugger_block_resize(&threads->stopped);
if (r < 0) {
rtems_debugger_thread_free(threads);
return true;
}
stopped = rtems_debugger_thread_stopped(threads);
stopped[threads->stopped.level++] = id;
}
else {
rtems_status_code sc;
sc = rtems_task_suspend(id);
if (sc != RTEMS_SUCCESSFUL && sc != RTEMS_ALREADY_SUSPENDED) {
rtems_debugger_printf("error: rtems-db: thread: suspend: %08lx: %s\n",
id, rtems_status_text(sc));
r = -1;
}
}
if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE))
rtems_debugger_printf("rtems-db: sys: thd: %08lx: signal: %d\n",
id, thread->signal);
/*
* Pick up the first non-zero signal.
*/
if (rtems_debugger->signal == 0) {
rtems_debugger->signal = thread->signal;
}
}
return false;
}
int
rtems_debugger_thread_system_suspend(void)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
int r = -1;
if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: sys: : suspending\n");
r = rtems_debugger_target_swbreak_remove();
if (r == 0) {
rtems_debugger_thread* current;
threads->current.level = 0;
threads->registers.level = 0;
threads->stopped.level = 0;
threads->excludes.level = 0;
threads->steppers.level = 0;
rtems_task_iterate(snapshot_thread, NULL);
current = rtems_debugger_thread_current(threads);
if (current == NULL) {
rtems_debugger_printf("error: rtems-db: thread: snapshot: (%d) %s\n",
errno, strerror(errno));
r = -1;
}
else {
rtems_id* stopped;
/*
* If there are no stopped threads pick the first one in the current
* table and return that.
*/
threads->selector_gen = 0;
threads->selector_cont = 0;
stopped = rtems_debugger_thread_stopped(threads);
if (threads->stopped.level == 0 && threads->current.level > 0) {
stopped[threads->stopped.level++] = current[0].id;
}
if (threads->stopped.level > 0) {
threads->selector_gen =
rtems_debugger_thread_find_index(stopped[0]);
if (threads->selector_gen < 0)
threads->selector_gen = 0;
}
}
}
else {
errno = EIO;
}
}
return r;
}
int
rtems_debugger_thread_system_resume(bool detaching)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread* current;
int r = 0;
current = rtems_debugger_thread_current(threads);
if (threads != NULL && current != NULL) {
size_t i;
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: sys: : resuming\n");
if (!detaching)
r = rtems_debugger_target_swbreak_insert();
if (r == 0) {
for (i = 0; i < threads->current.level; ++i) {
rtems_debugger_thread* thread = &current[i];
rtems_status_code sc;
int rr;
/*
* Check if resuming, which is continuing, a step, or stepping a range.
*/
if (detaching ||
rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_RESUME)) {
if (!detaching) {
rr = rtems_debugger_target_write_regs(thread);
if (rr < 0 && r == 0)
r = rr;
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
rr = rtems_debugger_target_thread_stepping(thread);
if (rr < 0 && r == 0)
r = rr;
}
}
sc = rtems_task_resume(thread->id);
if (sc != RTEMS_SUCCESSFUL) {
rtems_debugger_printf("error: rtems-db: thread: resume: %08lx: %s\n",
thread->id, rtems_status_text(sc));
}
thread->flags &= ~(RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE |
RTEMS_DEBUGGER_THREAD_FLAG_STEP);
thread->signal = 0;
}
}
/*
* Excludes are not cleared so the exception handler can find the
* excluded thread.
*/
threads->current.level = 0;
threads->registers.level = 0;
threads->stopped.level = 0;
}
else {
r = -1;
errno = EIO;
}
}
return r;
}
int
rtems_debugger_thread_continue(rtems_debugger_thread* thread)
{
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE;
return 0;
}
int
rtems_debugger_thread_continue_all(void)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread* current;
int r = 0;
current = rtems_debugger_thread_current(threads);
if (threads != NULL && current != NULL) {
size_t i;
for (i = 0; i < threads->current.level; ++i) {
rtems_debugger_thread* thread = &current[i];
int r;
r = rtems_debugger_thread_continue(thread);
if (r < 0)
break;
}
}
else {
r = -1;
errno = EIO;
}
return r;
}
int
rtems_debugger_thread_step(rtems_debugger_thread* thread)
{
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEP;
return 0;
}
int
rtems_debugger_thread_stepping(rtems_debugger_thread* thread,
DB_UINT start,
DB_UINT end)
{
/* add lock */
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread_stepper* stepper;
int r;
/*
* The resize will automatically extend the block when we are full. The
* steppers are cleared in suspend by setting the level to 0.
*/
r = rtems_debugger_block_resize(&threads->steppers);
if (r < 0) {
rtems_debugger_thread_free(threads);
return -1;
}
stepper = rtems_debugger_thread_steppers(threads);
stepper = &stepper[threads->steppers.level];
stepper->thread = thread;
stepper->start = start;
stepper->end = end;
threads->steppers.level++;
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEPPING;
return 0;
}
const rtems_debugger_thread_stepper*
rtems_debugger_thread_is_stepping(rtems_id id, DB_UINT pc)
{
/* add lock */
rtems_debugger_threads* threads = rtems_debugger->threads;
rtems_debugger_thread_stepper* stepper;
size_t i;
stepper = rtems_debugger_thread_steppers(threads);
for (i = 0; i < threads->steppers.level; ++i, ++stepper) {
if (stepper->thread->id == id) {
if (pc == stepper->start || (pc > stepper->start && pc < stepper->end))
return stepper;
break;
}
}
return NULL;
}
int
rtems_debugger_thread_current_priority(rtems_debugger_thread* thread)
{
return _Thread_Get_priority(thread->tcb);
}
int
rtems_debugger_thread_real_priority(rtems_debugger_thread* thread)
{
return thread->tcb->Real_priority.priority;
}
int
rtems_debugger_thread_state(rtems_debugger_thread* thread)
{
return thread->tcb->current_state;
}
int
rtems_debugger_thread_state_str(rtems_debugger_thread* thread,
char* buffer,
size_t size)
{
struct mapper {
const char const* label;
DB_UINT mask;
};
const struct mapper map[] = {
{ "DELAY", STATES_DELAYING },
{ "DORM", STATES_DORMANT },
{ "LIFE", STATES_LIFE_IS_CHANGING },
{ "SUSP", STATES_SUSPENDED },
{ "Wbar", STATES_WAITING_FOR_BARRIER },
{ "Wbuf", STATES_WAITING_FOR_BUFFER },
{ "Wcvar", STATES_WAITING_FOR_CONDITION_VARIABLE },
{ "Wevnt", STATES_WAITING_FOR_EVENT },
{ "Wisig", STATES_INTERRUPTIBLE_BY_SIGNAL },
{ "Wjatx", STATES_WAITING_FOR_JOIN_AT_EXIT },
{ "Wjoin", STATES_WAITING_FOR_JOIN },
{ "Wmsg" , STATES_WAITING_FOR_MESSAGE },
{ "Wmutex", STATES_WAITING_FOR_MUTEX },
{ "WRATE", STATES_WAITING_FOR_PERIOD },
{ "Wrpc", STATES_WAITING_FOR_RPC_REPLY },
{ "Wrwlk", STATES_WAITING_FOR_RWLOCK },
{ "Wseg", STATES_WAITING_FOR_SEGMENT },
{ "Wsem", STATES_WAITING_FOR_SEMAPHORE },
{ "Wsig", STATES_WAITING_FOR_SIGNAL },
{ "Wslcnd", STATES_WAITING_FOR_SYS_LOCK_CONDITION },
{ "Wslftx", STATES_WAITING_FOR_SYS_LOCK_FUTEX },
{ "Wslmtx", STATES_WAITING_FOR_SYS_LOCK_MUTEX },
{ "Wslsem", STATES_WAITING_FOR_SYS_LOCK_SEMAPHORE },
{ "Wsysev", STATES_WAITING_FOR_SYSTEM_EVENT },
{ "Wtime", STATES_WAITING_FOR_TIME },
{ "Wwkup", STATES_WAITING_FOR_BSD_WAKEUP },
{ "ZOMBI", STATES_ZOMBIE },
};
DB_UINT state = thread->tcb->current_state;
if (state == STATES_READY) {
strcpy(buffer, "READY");
}
else {
char* start = buffer;
size_t i;
buffer[0] = '\0';
buffer[size - 1] = '\0';
for (i = 0; size > 0 && i < RTEMS_DEBUGGER_NUMOF(map); ++i) {
if ((map[i].mask & state) != 0) {
size_t l = snprintf(buffer, size - 1, "%s ", map[i].label);
buffer += l;
size -= l;
}
}
if (buffer != start)
*(buffer - 1) = '\0';
}
return 0;
}
unsigned long
rtems_debugger_thread_stack_size(rtems_debugger_thread* thread)
{
return thread->tcb->Start.Initial_stack.size;
}
void*
rtems_debugger_thread_stack_area(rtems_debugger_thread* thread)
{
return thread->tcb->Start.Initial_stack.area;
}

View File

@@ -0,0 +1,272 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_THREADS_h
#define _RTEMS_DEBUGGER_THREADS_h
#include <rtems/debugger/rtems-debugger-server.h>
#include "rtems-debugger-block.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Debugger thread name size, fixed size. ASCIIZ format.
*/
#define RTEMS_DEBUGGER_THREAD_NAME_SIZE (5)
/**
* Debugger thread allocation block size.
*/
#define RTEMS_DEBUGGER_THREAD_BLOCK_SIZE (32)
/**
* Debugger thread flags.
*/
#define RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING (1 << 0)
#define RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID (1 << 1)
#define RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY (1 << 2)
#define RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE (1 << 3)
#define RTEMS_DEBUGGER_THREAD_FLAG_STEP (1 << 4)
#define RTEMS_DEBUGGER_THREAD_FLAG_STEPPING (1 << 5)
#define RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED (1 << 6)
/* Target specific flags for use by the target backend. */
#define RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE (24)
#define RTEMS_DEBUGGER_THREAD_FLAG_TARGET_MASK (0xff << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE)
/**
* Resume this thread.
*/
#define RTEMS_DEBUGGER_THREAD_FLAG_RESUME \
(RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE | \
RTEMS_DEBUGGER_THREAD_FLAG_STEP | \
RTEMS_DEBUGGER_THREAD_FLAG_STEPPING)
/**
* Step an instruction.
*/
#define RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR \
(RTEMS_DEBUGGER_THREAD_FLAG_STEP | \
RTEMS_DEBUGGER_THREAD_FLAG_STEPPING)
/**
* Debugger thread.
*/
typedef struct rtems_debugger_thread
{
uint32_t flags;
const char name[RTEMS_DEBUGGER_THREAD_NAME_SIZE];
Thread_Control* tcb;
rtems_id id;
int cpu;
DB_UINT* registers;
int signal;
void* frame;
} rtems_debugger_thread;
/**
* Debugger stepping thread. This is a thread that steps while inside an
* address range.
*/
typedef struct rtems_debugger_thread_stepper
{
rtems_debugger_thread* thread;
DB_UINT start;
DB_UINT end;
} rtems_debugger_thread_stepper;
/**
* Debugger thread control.
*/
struct rtems_debugger_threads
{
rtems_debugger_block current; /**< The threads currently available. */
rtems_debugger_block registers; /**< The threads that have stopped. */
rtems_debugger_block excludes; /**< The threads we cannot touch. */
rtems_debugger_block stopped; /**< The threads that have stopped. */
rtems_debugger_block steppers; /**< The threads that are stepping. */
size_t next; /**< An iterator. */
int selector_gen; /**< General thread selector. */
int selector_cont; /**< Continue thread selector. */
};
/**
* Create the thread support.
*/
extern int rtems_debugger_thread_create(void);
/**
* Destroy the thread support.
*/
extern int rtems_debugger_thread_destroy(void);
/**
* Find the index in the thread table for the ID.
*/
extern int rtems_debugger_thread_find_index(rtems_id id);
/**
* Suspend the system.
*/
extern int rtems_debugger_thread_system_suspend(void);
/**
* Resume the system.
*/
extern int rtems_debugger_thread_system_resume(bool detaching);
/**
* Continue all threads.
*/
extern int rtems_debugger_thread_continue_all(void);
/**
* Continue a thread.
*/
extern int rtems_debugger_thread_continue(rtems_debugger_thread* thread);
/**
* Step a thread.
*/
extern int rtems_debugger_thread_step(rtems_debugger_thread* thread);
/**
* Thread is stepping so record the details.
*/
extern int rtems_debugger_thread_stepping(rtems_debugger_thread* thread,
DB_UINT start,
DB_UINT end);
/**
* Thread's PC in the stepping range? Returns the stepper is in range else
* NULL.
*/
extern const rtems_debugger_thread_stepper*
rtems_debugger_thread_is_stepping(rtems_id id, DB_UINT pc);
/**
* Return the thread's current priority/
*/
extern int rtems_debugger_thread_current_priority(rtems_debugger_thread* thread);
/**
* Return the thread's real priority.
*/
extern int rtems_debugger_thread_real_priority(rtems_debugger_thread* thread);
/**
* Return the thread's state.
*/
extern int rtems_debugger_thread_state(rtems_debugger_thread* thread);
/**
* Return the thread's state.
*/
//extern bool rtems_debugger_thread_state_debugger(rtems_debugger_thread* thread);
/**
* Return a string of the thread's state.
*/
extern int rtems_debugger_thread_state_str(rtems_debugger_thread* thread,
char* buffer,
size_t size);
/**
* Return the thread's stack size.
*/
extern unsigned long rtems_debugger_thread_stack_size(rtems_debugger_thread* thread);
/**
* Return the thread's stack area address.
*/
extern void* rtems_debugger_thread_stack_area(rtems_debugger_thread* thread);
/**
* Check a thread's flag and return true if any of the bits in the mask are
* set.
*/
static inline bool
rtems_debugger_thread_flag(rtems_debugger_thread* thread,
uint32_t mask)
{
return (thread->flags & mask) != 0;
}
/**
* Get the current threads.
*/
static inline rtems_debugger_thread*
rtems_debugger_thread_current(rtems_debugger_threads* threads)
{
return threads->current.block;
}
/**
* Get the registers.
*/
static inline DB_UINT*
rtems_debugger_thread_registers(rtems_debugger_threads* threads)
{
return threads->registers.block;
}
/**
* Get the excludes.
*/
static inline rtems_id*
rtems_debugger_thread_excludes(rtems_debugger_threads* threads)
{
return threads->excludes.block;
}
/**
* Get the stopped.
*/
static inline rtems_id*
rtems_debugger_thread_stopped(rtems_debugger_threads* threads)
{
return threads->stopped.block;
}
/**
* Get the steppers.
*/
static inline rtems_debugger_thread_stepper*
rtems_debugger_thread_steppers(rtems_debugger_threads* threads)
{
return threads->steppers.block;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger for RTEMS.
*/
#ifndef _RTEMS_DEBUGGER_h
#define _RTEMS_DEBUGGER_h
#include <stdbool.h>
#include <rtems.h>
#include <rtems/printer.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Timeout period for an ack
*/
#define RTEMS_DEBUGGER_TIMEOUT (3)
/**
* Start the Debugger.
*/
extern int rtems_debugger_start(const char* remote,
const char* device,
int timeout,
rtems_task_priority priority,
const rtems_printer* printer);
/**
* Stop the Debugger.
*/
extern int rtems_debugger_stop(void);
/**
* Is the Debugger running?.
*/
extern bool rtems_debugger_running(void);
/**
* Verbose control.
*/
extern void rtems_debugger_set_verbose(bool on);
/**
* Control remote debug printing.
*/
extern int rtems_debugger_remote_debug(bool state);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -233,6 +233,24 @@ $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h: libdl/rap-shell.h $(PROJECT_INCLUDE)/r
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtl/rap-shell.h
endif endif
if LIBDEBUGGER
$(PROJECT_INCLUDE)/rtems/rtems-debugger.h: libdebugger/rtems-debugger.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-debugger.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-debugger.h
$(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/debugger
@: > $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
$(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h: libdebugger/rtems-debugger-server.h $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-server.h
$(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h: libdebugger/rtems-debugger-remote.h $(PROJECT_INCLUDE)/rtems/debugger/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/debugger/rtems-debugger-remote.h
endif
$(PROJECT_INCLUDE)/rtems/bspIo.h: include/rtems/bspIo.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(PROJECT_INCLUDE)/rtems/bspIo.h: include/rtems/bspIo.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bspIo.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bspIo.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bspIo.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bspIo.h

View File

@@ -95,6 +95,10 @@ if LIBDL
TMP_LIBS += ../libdl/libdl.a TMP_LIBS += ../libdl/libdl.a
endif endif
if LIBDEBUGGER
TMP_LIBS += ../libdebugger/libdebugger.a
endif
librtemscpu.a: $(TMP_LIBS) librtemscpu.a: $(TMP_LIBS)
rm -f $@ rm -f $@
$(MKDIR_P) $(ARCH) $(MKDIR_P) $(ARCH)

View File

@@ -53,5 +53,9 @@ _SUBDIRS += dl04 dl05
endif endif
endif endif
if DEBUGGERTESTS
_SUBDIRS += debugger01
endif
include $(top_srcdir)/../automake/test-subdirs.am include $(top_srcdir)/../automake/test-subdirs.am
include $(top_srcdir)/../automake/local.am include $(top_srcdir)/../automake/local.am

View File

@@ -80,6 +80,17 @@ AS_IF([test x"$TEST_LIBDL" = x"yes"],[
AM_CONDITIONAL(DLTESTS,[test x"$TEST_LIBDL" = x"yes"]) AM_CONDITIONAL(DLTESTS,[test x"$TEST_LIBDL" = x"yes"])
# Must match the list in cpukit.
AC_MSG_CHECKING([whether CPU supports libdebugger])
case $RTEMS_CPU in
arm | i386)
TEST_LIBDEBUGGER=yes ;;
*)
TEST_LIBDEBUGGER=no ;;
esac
AC_MSG_RESULT([$TEST_LIBDEBUGGER])
AM_CONDITIONAL(DEBUGGERTESTS,[test x"$TEST_LIBDEBUGGER" = x"yes"])
# Explicitly list all Makefiles here # Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
networking01/Makefile networking01/Makefile
@@ -169,5 +180,6 @@ math/Makefile
mathf/Makefile mathf/Makefile
mathl/Makefile mathl/Makefile
complex/Makefile complex/Makefile
debugger01/Makefile
]) ])
AC_OUTPUT AC_OUTPUT

View File

@@ -0,0 +1,21 @@
rtems_tests_PROGRAMS = debugger01
debugger01_SOURCES = init.c remote.c system.h
dist_rtems_tests_DATA = debugger01.scn
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(debugger01_OBJECTS)
LINK_LIBS = $(debugger01_LDLIBS)
debugger01$(EXEEXT): $(debugger01_OBJECTS) $(debugger01_DEPENDENCIES)
@rm -f debugger01$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am

View File

@@ -0,0 +1,18 @@
# Copyright (c) 2016 Chris Johns <chrisj@rtems.org>
#
# The license and distribution terms for this file may be
# found in the file LICENSE in this distribution or at
# http://www.rtems.org/license/LICENSE.
#
This file describes the directives and concepts tested by this test set.
test set name: debugger01
directives:
rtems_debugger_start
concepts:
+ Starts a debugging session with the test remote backend.

View File

@@ -0,0 +1,188 @@
*** BEGIN OF TEST DEBUGGER01 ***
error: rtems-db: remote not found: test
error: rtems-db: test remote: begin
rtems-db: remote-debug is on
rtems-db: remote running
rtems-db: test remote: isconnected: not-connected
error: rtems-db: test remote: connect
rtems-db: remote running
rtems-db: arm debug: (v3.0) ARMv7 [v7, all CP14 registers] breakpoints:5
watchpoints:3
rtems-db: sys: : suspending
rtems-db: sys: thd: 0a010001: signal: 0
rtems-db: test remote: isconnected: connected
remote: rx: message=0 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK?]]
remote: rx: message=1 length=5
remote: rx: xxxxx
remote: rx: message=2 length=5
remote: rx: $x#aa
rtems-db: get: 5: xxxxx [[junk dropped]]
rtems-db: get: : $x#aa [[invalid checksum]]
rtems-db: put: 1: -
remote: tx: message=0 length=1
remote: tx: -
remote: rx: message=3 length=141
remote: rx: $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df
rtems-db: get: 141: [[junk dropped]]
rtems-db: get: : $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df
rtems-db: put: 1: +
remote: tx: message=1 length=1
remote: tx: +
rtems-db: put: 167: $qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;QThreadEvents-;no-resumed+#b3
remote: tx: message=2 length=167
remote: tx: $qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;QThreadEvents-;no-resumed+#b3
rtems-db: test remote: isconnected: connected
remote: rx: message=4 length=19
remote: rx: $vMustReplyEmpty#3a
rtems-db: get: 19: $vMustReplyEmpty#3a
rtems-db: put: 1: +
remote: tx: message=3 length=1
remote: tx: +
rtems-db: put: 4: $#00
remote: tx: message=4 length=4
remote: tx: $#00
rtems-db: test remote: isconnected: connected
remote: rx: message=5 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=6 length=10
remote: rx: $Hgp0.0#ad
rtems-db: get: 10: $Hgp0.0#ad
rtems-db: put: 1: +
remote: tx: message=5 length=1
remote: tx: +
rtems-db: put: 6: $OK#9a
remote: tx: message=6 length=6
remote: tx: $OK#9a
rtems-db: test remote: isconnected: connected
remote: rx: message=7 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=8 length=12
remote: rx: $qTStatus#49
rtems-db: get: 12: $qTStatus#49
rtems-db: put: 1: +
remote: tx: message=7 length=1
remote: tx: +
rtems-db: put: 4: $#00
remote: tx: message=8 length=4
remote: tx: $#00
rtems-db: test remote: isconnected: connected
remote: rx: message=9 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=10 length=5
remote: rx: $?#3f
rtems-db: get: 5: $?#3f
rtems-db: put: 1: +
remote: tx: message=9 length=1
remote: tx: +
rtems-db: put: 26: $T00thread:p1.0a010001;#23
remote: tx: message=10 length=26
remote: tx: $T00thread:p1.0a010001;#23
rtems-db: test remote: isconnected: connected
remote: rx: message=11 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=12 length=16
remote: rx: $qfThreadInfo#bb
rtems-db: get: 16: $qfThreadInfo#bb
rtems-db: put: 1: +
remote: tx: message=11 length=1
remote: tx: +
rtems-db: put: 16: $mp1.0a010001#ef
remote: tx: message=12 length=2
remote: tx: $mp1.0a010001#ef
rtems-db: test remote: isconnected: connected
remote: rx: message=13 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=14 length=16
remote: rx: $qsThreadInfo#c8
rtems-db: get: 16: $qsThreadInfo#c8
rtems-db: put: 1: +
remote: tx: message=13 length=1
remote: tx: +
rtems-db: put: 5: $l#6c
remote: tx: message=14 length=5
remote: tx: $l#6c
rtems-db: test remote: isconnected: connected
remote: rx: message=15 length=1
remote: rx: -
rtems-db: get: 1: - [[NACK]]
rtems-db: put: 5: $l#6c
remote: tx: message=15 length=5
remote: tx: $l#6c
remote: rx: message=16 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=17 length=15
remote: rx: $qAttached:1#fa
rtems-db: get: 15: $qAttached:1#fa
rtems-db: put: 1: +
remote: tx: message=16 length=1
remote: tx: +
rtems-db: put: 5: $1#31
remote: tx: message=17 length=5
remote: tx: $1#31
rtems-db: test remote: isconnected: connected
remote: rx: message=18 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=19 length=8
remote: rx: $Hc-1#09
rtems-db: get: 8: $Hc-1#09
rtems-db: put: 1: +
remote: tx: message=18 length=1
remote: tx: +
rtems-db: put: 6: $OK#9a
remote: tx: message=19 length=6
remote: tx: $OK#9a
rtems-db: test remote: isconnected: connected
remote: rx: message=20 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=21 length=12
remote: rx: $qOffsets#4b
rtems-db: get: 12: $qOffsets#4b
rtems-db: put: 1: +
remote: tx: message=20 length=1
remote: tx: +
rtems-db: put: 4: $#00
remote: tx: message=21 length=4
remote: tx: $#00
rtems-db: test remote: isconnected: connected
remote: rx: message=22 length=1
remote: rx: +
rtems-db: get: 1: + [[ACK]]
remote: rx: message=23 length=6
remote: rx: $g#67+
rtems-db: get: 6: $g#67
rtems-db: put: 1: +
remote: tx: message=22 length=1
remote: tx: +
+ [[extra data: 0x2b]]rtems-db: put: 212: $cc381200cc381200cc381200cc3812004c162000a83f2000704520004c16200040362000481620000000000020ee1100cc38120028a2200089dc100089dc1000cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200#95
remote: tx: message=23 length=2
remote: tx: $cc381200cc381200cc381200cc3812004c162000a83f2000704520004c16200040362000481620000000000020ee1100cc38120028a2200089dc100089dc1000cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc381200cc3812g00cc381200#95
rtems-db: test remote: isconnected: connected
remote: rx: message=24 length=7
remote: rx: $D;1#b0
rtems-db: get: 7: $D;1#b0
rtems-db: put: 1: +
remote: tx: message=24 length=1
remote: tx: +
rtems-db: put: 6: $OK#9a
remote: tx: message=25 length=6
remote: tx: $OK#9a
rtems-db: test remote: isconnected: connected
rtems-db: test remote: disconnect host
rtems-db: test remote: isconnected: not-connected
rtems-db: events running
rtems-db: events finishing
rtems-db: sys: : resuming
rtems-db: test remote: isconnected: not-connected
rtems-db: test remote: isconnected: not-connected
*** END OF TEST DEBUGGER01 ***

View File

@@ -0,0 +1,53 @@
/*
* Debugger test.
*
* Copyright (c) 2016 Chris Johns (chrisj@rtems.org)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define CONFIGURE_INIT
#include "system.h"
#include "tmacros.h"
#include <rtems/rtems-debugger.h>
#include "system.h"
static void test(void)
{
rtems_printer printer;
rtems_print_printer_fprintf(&printer, stdout);
rtems_test_assert(rtems_debugger_start("test", "something",
3, 10, &printer) < 0);
rtems_test_assert(rtems_debugger_register_test_remote() == 0);
rtems_test_assert(rtems_debugger_start("test", "something",
3, 10, &printer) == 0);
rtems_debugger_set_verbose(true);
rtems_test_assert(rtems_debugger_remote_debug(true) == 0);
/*
* This thread is suspended when the debugger is active until the debugger
* disconnects.
*/
sleep(1);
}
const char rtems_test_name[] = "DEBUGGER01";
rtems_task Init(rtems_task_argument argument)
{
TEST_BEGIN();
test();
TEST_END();
}

View File

@@ -0,0 +1,321 @@
/*
* Debugger test remote.
*
* Copyright (c) 2016 Chris Johns (chrisj@rtems.org)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tmacros.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <rtems/rtems-debugger.h>
#include <rtems/debugger/rtems-debugger-server.h>
#include <rtems/debugger/rtems-debugger-remote.h>
#include "system.h"
/**
* Remote data.
*/
typedef struct
{
int connect_count;
bool connected;
size_t out;
size_t in;
} rtems_debugger_remote_test;
static const char* out[] =
{
"+",
"xxxxx",
"$x#aa",
"$qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;"
"vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df",
"$vMustReplyEmpty#3a",
"+",
"$Hgp0.0#ad",
"+",
"$qTStatus#49",
"+",
"$?#3f",
"+",
"$qfThreadInfo#bb",
"+",
"$qsThreadInfo#c8",
"-",
"+",
"$qAttached:1#fa",
"+",
"$Hc-1#09",
"+",
"$qOffsets#4b",
"+",
"$g#67"
"+",
"$D;1#b0",
"+"
};
static const char* in[] =
{
/* 0 */
"-",
/* 1 */
"+",
"$qSupported:PacketSize=4096;QNonStop-;multiprocess+;swbreak+;hwbreak-;"
"qRelocInsn-;fork-events-;vfork-events-;exec-events-;vContSupported+;"
"QThreadEvents-;no-resumed+#b3",
/* 3 */
"+",
"$#00",
/* 5 */
"+",
"$OK#9a",
/* 7 */
"+",
"$#00",
/* 9 */
"+",
"$T00thread:p1.0a010001;#23",
/* 11 */
"+",
"**",
/* 13 */
"+",
"$l#6c",
"$l#6c",
/* 16 */
"+",
"$1#31",
/* 18 */
"+",
"$OK#9a",
/* 20 */
"+",
"$#00",
/* 22 */
"+",
"**",
"+",
"$OK#9a"
};
static int
test_remote_begin(rtems_debugger_remote* remote, const char* device)
{
rtems_debugger_remote_test* test;
rtems_debugger_printf("error: rtems-db: test remote: begin\n");
rtems_debugger_lock();
/*
* Check the device.
*/
rtems_test_assert(strcmp(device, "something") == 0);
test = malloc(sizeof(rtems_debugger_remote_test));
rtems_test_assert(test != NULL);
remote->data = test;
test->connect_count = 0;
test->connected = false;
test->out = 0;
test->in = 0;
rtems_debugger_unlock();
return 0;
}
static int
test_remote_end(rtems_debugger_remote* remote)
{
rtems_debugger_remote_test* test;
rtems_debugger_printf("error: rtems-db: test remote: end\n");
rtems_debugger_lock();
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
test->connected = false;
free(test);
rtems_debugger_unlock();
return 0;
}
static int
test_remote_connect(rtems_debugger_remote* remote)
{
rtems_debugger_remote_test* test;
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
if (test->connect_count > 0) {
rtems_event_set out = 0;
rtems_test_assert(rtems_event_receive(RTEMS_EVENT_1,
RTEMS_EVENT_ALL | RTEMS_WAIT,
RTEMS_NO_TIMEOUT,
&out) == RTEMS_SUCCESSFUL);
}
rtems_debugger_printf("error: rtems-db: test remote: connect\n");
++test->connect_count;
test->connected = true;
test->out = 0;
test->in = 0;
return 0;
}
static int
test_remote_disconnect(rtems_debugger_remote* remote)
{
rtems_debugger_remote_test* test;
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
rtems_debugger_printf("rtems-db: test remote: disconnect host\n");
rtems_debugger_lock();
rtems_test_assert(test->connected == true);
test->connected = false;
rtems_debugger_unlock();
return 0;
}
static bool
test_remote_isconnected(rtems_debugger_remote* remote)
{
rtems_debugger_remote_test* test;
bool isconnected;
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
isconnected = test != NULL && test->connected;
rtems_debugger_printf("rtems-db: test remote: isconnected: %s\n",
isconnected ? "connected" : "not-connected");
return isconnected;
}
static void
test_remote_print(const char* label, const char* buf, size_t size)
{
printf(" remote: %s: ", label);
while (size-- > 0) {
printf("%c", *buf++);
}
printf("\n");
}
static ssize_t
test_remote_receive(rtems_debugger_remote* remote,
void* buf,
size_t nbytes)
{
rtems_debugger_remote_test* test;
size_t len;
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
rtems_test_assert(test->out < RTEMS_DEBUGGER_NUMOF(out));
len = strlen(out[test->out]);
printf(" remote: rx: message=%zu length=%zu\n", test->out, len);
test_remote_print("rx", out[test->out], len);
rtems_test_assert(len < nbytes);
memcpy(buf, out[test->out++], len);
return len;
}
static ssize_t
test_remote_send(rtems_debugger_remote* remote,
const void* buf,
size_t nbytes)
{
rtems_debugger_remote_test* test;
size_t len;
bool no_match;
rtems_test_assert(remote != NULL);
rtems_test_assert(remote->data != NULL);
test = (rtems_debugger_remote_test*) remote->data;
rtems_test_assert(test->in < RTEMS_DEBUGGER_NUMOF(in));
len = strlen(in[test->in]);
no_match = len == 2 && strcmp(in[test->in], "**") == 0;
printf(" remote: tx: message=%zu length=%zu\n", test->in, len);
if (!no_match)
rtems_test_assert(len == nbytes);
test_remote_print("tx", buf, nbytes);
if (!no_match)
rtems_test_assert(memcmp(buf, in[test->in], nbytes) == 0);
test->in++;
return nbytes;
}
static rtems_debugger_remote remote_test =
{
.name = "test",
.begin = test_remote_begin,
.end = test_remote_end,
.connect = test_remote_connect,
.disconnect = test_remote_disconnect,
.isconnected = test_remote_isconnected,
.read = test_remote_receive,
.write = test_remote_send
};
int
rtems_debugger_register_test_remote(void)
{
return rtems_debugger_remote_register(&remote_test);
}

View File

@@ -0,0 +1,37 @@
/* system.h
*
* This include file contains information that is included in every
* function in the test set.
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <tmacros.h>
/* functions */
rtems_task Init(rtems_task_argument argument);
int rtems_debugger_register_test_remote(void);
void test_wake(void);
/* configuration information */
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
#define CONFIGURE_MAXIMUM_TASKS 10
#define CONFIGURE_MAXIMUM_SEMAPHORES 10
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#include <rtems/confdefs.h>
/* end of include file */