forked from Imagelibrary/rtems
cpukit: Add libdebugger, a remote debugger agent for GDB.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
23
cpukit/libdebugger/Makefile.am
Normal file
23
cpukit/libdebugger/Makefile.am
Normal 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
|
||||||
9
cpukit/libdebugger/preinstall.am
Normal file
9
cpukit/libdebugger/preinstall.am
Normal 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
|
||||||
1193
cpukit/libdebugger/rtems-debugger-arm.c
Normal file
1193
cpukit/libdebugger/rtems-debugger-arm.c
Normal file
File diff suppressed because it is too large
Load Diff
73
cpukit/libdebugger/rtems-debugger-block.c
Normal file
73
cpukit/libdebugger/rtems-debugger-block.c
Normal 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;
|
||||||
|
}
|
||||||
75
cpukit/libdebugger/rtems-debugger-block.h
Normal file
75
cpukit/libdebugger/rtems-debugger-block.h
Normal 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
|
||||||
208
cpukit/libdebugger/rtems-debugger-cmd.c
Normal file
208
cpukit/libdebugger/rtems-debugger-cmd.c
Normal 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
|
||||||
|
};
|
||||||
421
cpukit/libdebugger/rtems-debugger-i386.c
Normal file
421
cpukit/libdebugger/rtems-debugger-i386.c
Normal 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;
|
||||||
|
}
|
||||||
342
cpukit/libdebugger/rtems-debugger-remote-tcp.c
Normal file
342
cpukit/libdebugger/rtems-debugger-remote-tcp.c
Normal 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);
|
||||||
|
}
|
||||||
47
cpukit/libdebugger/rtems-debugger-remote-tcp.h
Normal file
47
cpukit/libdebugger/rtems-debugger-remote-tcp.h
Normal 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
|
||||||
68
cpukit/libdebugger/rtems-debugger-remote.c
Normal file
68
cpukit/libdebugger/rtems-debugger-remote.c
Normal 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;
|
||||||
|
}
|
||||||
71
cpukit/libdebugger/rtems-debugger-remote.h
Normal file
71
cpukit/libdebugger/rtems-debugger-remote.h
Normal 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
|
||||||
1993
cpukit/libdebugger/rtems-debugger-server.c
Normal file
1993
cpukit/libdebugger/rtems-debugger-server.c
Normal file
File diff suppressed because it is too large
Load Diff
204
cpukit/libdebugger/rtems-debugger-server.h
Normal file
204
cpukit/libdebugger/rtems-debugger-server.h
Normal 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
|
||||||
400
cpukit/libdebugger/rtems-debugger-target.c
Normal file
400
cpukit/libdebugger/rtems-debugger-target.c
Normal 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;
|
||||||
|
}
|
||||||
237
cpukit/libdebugger/rtems-debugger-target.h
Normal file
237
cpukit/libdebugger/rtems-debugger-target.h
Normal 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
|
||||||
577
cpukit/libdebugger/rtems-debugger-threads.c
Normal file
577
cpukit/libdebugger/rtems-debugger-threads.c
Normal 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 = ¤t[threads->current.level++];
|
||||||
|
thread->registers =
|
||||||
|
®isters[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 = ¤t[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 = ¤t[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;
|
||||||
|
}
|
||||||
272
cpukit/libdebugger/rtems-debugger-threads.h
Normal file
272
cpukit/libdebugger/rtems-debugger-threads.h
Normal 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
|
||||||
81
cpukit/libdebugger/rtems-debugger.h
Normal file
81
cpukit/libdebugger/rtems-debugger.h
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
21
testsuites/libtests/debugger01/Makefile.am
Normal file
21
testsuites/libtests/debugger01/Makefile.am
Normal 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
|
||||||
18
testsuites/libtests/debugger01/debugger01.doc
Normal file
18
testsuites/libtests/debugger01/debugger01.doc
Normal 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.
|
||||||
188
testsuites/libtests/debugger01/debugger01.scn
Normal file
188
testsuites/libtests/debugger01/debugger01.scn
Normal 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 ***
|
||||||
53
testsuites/libtests/debugger01/init.c
Normal file
53
testsuites/libtests/debugger01/init.c
Normal 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();
|
||||||
|
}
|
||||||
321
testsuites/libtests/debugger01/remote.c
Normal file
321
testsuites/libtests/debugger01/remote.c
Normal 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);
|
||||||
|
}
|
||||||
37
testsuites/libtests/debugger01/system.h
Normal file
37
testsuites/libtests/debugger01/system.h
Normal 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 */
|
||||||
Reference in New Issue
Block a user