forked from Imagelibrary/rtems
libdebugger: Fixes to debugging, ARM support, locking, and gcc-7.1 warnings.
- Add `printk` support to aid multi-core debugging. - Add lock trace to aid lock debugging. - Fixes to gcc-7.1 warnings. - Fixes from ticket #2879. - Add verbose command controls. - Change using the RTEMS sys/lock.h API to manage exception threads. - ARM hardware breakpoint fixes. Support for SMP stepping is not implemented, this requires use of the context id register. Closes #2879.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
|
||||
* Copyright (c) 2016-2017 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
|
||||
@@ -23,10 +24,16 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define RTEMS_DEBUGGER_VERBOSE_LOCK 0
|
||||
#define RTEMS_DEBUGGER_PRINT_PRINTK 1
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/score/smp.h>
|
||||
|
||||
#include <rtems/rtems-debugger.h>
|
||||
#include <rtems/debugger/rtems-debugger-server.h>
|
||||
#include <rtems/debugger/rtems-debugger-remote.h>
|
||||
@@ -50,15 +57,15 @@ typedef int (*rtems_debugger_command)(uint8_t* buffer, int size);
|
||||
|
||||
typedef struct rtems_debugger_packet
|
||||
{
|
||||
const char const* label;
|
||||
const char* const label;
|
||||
rtems_debugger_command command;
|
||||
} rtems_debugger_packet;
|
||||
|
||||
/**
|
||||
* Common error strings.
|
||||
*/
|
||||
static const char const* r_OK = "OK";
|
||||
static const char const* r_E01 = "E01";
|
||||
static const char* const r_OK = "OK";
|
||||
static const char* const r_E01 = "E01";
|
||||
|
||||
/*
|
||||
* Global Debugger.
|
||||
@@ -73,13 +80,59 @@ static const char const* r_E01 = "E01";
|
||||
*/
|
||||
rtems_debugger_server* rtems_debugger;
|
||||
|
||||
/**
|
||||
* Print lock ot make the prints sequential. This is to debug the debugger in
|
||||
* SMP.
|
||||
*/
|
||||
#if RTEMS_DEBUGGER_PRINT_PRINTK
|
||||
RTEMS_INTERRUPT_LOCK_DEFINE(static, printk_lock, "printk_lock")
|
||||
#endif
|
||||
|
||||
void
|
||||
rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context)
|
||||
{
|
||||
rtems_interrupt_lock_acquire(&printk_lock, lock_context);
|
||||
}
|
||||
|
||||
void
|
||||
rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context)
|
||||
{
|
||||
rtems_interrupt_lock_release(&printk_lock, lock_context);
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_clean_printf(const char* format, ...)
|
||||
{
|
||||
int len;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
if (RTEMS_DEBUGGER_PRINT_PRINTK) {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
rtems_debugger_printk_lock(&lock_context);
|
||||
len = vprintk(format, ap);
|
||||
rtems_debugger_printk_unlock(&lock_context);
|
||||
}
|
||||
else
|
||||
len = rtems_vprintf(&rtems_debugger->printer, format, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_printf(const char* format, ...)
|
||||
{
|
||||
int len;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
len = rtems_vprintf(&rtems_debugger->printer, format, ap);
|
||||
if (RTEMS_DEBUGGER_PRINT_PRINTK) {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
rtems_debugger_printk_lock(&lock_context);
|
||||
printk("[CPU:%d] ", (int) _SMP_Get_current_processor ());
|
||||
len = vprintk(format, ap);
|
||||
rtems_debugger_printk_unlock(&lock_context);
|
||||
}
|
||||
else
|
||||
len = rtems_vprintf(&rtems_debugger->printer, format, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
@@ -158,74 +211,31 @@ thread_id_decode(const char* data, DB_UINT* pid, DB_UINT* tid)
|
||||
static inline bool
|
||||
check_pid(DB_UINT pid)
|
||||
{
|
||||
return pid == 0|| rtems_debugger->pid == (pid_t) pid;
|
||||
return pid == 0 || rtems_debugger->pid == (pid_t) pid;
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
rtems_debugger_lock(void)
|
||||
{
|
||||
if (rtems_debugger->lock != 0) {
|
||||
rtems_status_code sc;
|
||||
sc = rtems_semaphore_obtain(rtems_debugger->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: lock: %s\n",
|
||||
rtems_status_text(sc));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
_Mutex_recursive_Acquire(&rtems_debugger->lock);
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
rtems_debugger_unlock(void)
|
||||
{
|
||||
if (rtems_debugger->lock != 0) {
|
||||
rtems_status_code sc;
|
||||
sc = rtems_semaphore_release(rtems_debugger->lock);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: unlock: %s\n",
|
||||
rtems_status_text(sc));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
_Mutex_recursive_Release(&rtems_debugger->lock);
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_debugger_lock_create(void)
|
||||
{
|
||||
#define LOCK_ATTRIBUTES \
|
||||
RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE
|
||||
rtems_status_code sc;
|
||||
sc = rtems_semaphore_create(rtems_build_name('G', 'D', 'B', 's'),
|
||||
1,
|
||||
LOCK_ATTRIBUTES,
|
||||
0,
|
||||
&rtems_debugger->lock);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: sema create: %s\n",
|
||||
rtems_status_text(sc));
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
_Mutex_recursive_Initialize_named(&rtems_debugger->lock, "DBlock");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_debugger_lock_destroy(void)
|
||||
{
|
||||
rtems_debugger_lock();
|
||||
if (rtems_debugger->lock != 0) {
|
||||
rtems_status_code sc;
|
||||
rtems_semaphore_release(rtems_debugger->lock);
|
||||
sc = rtems_semaphore_delete(rtems_debugger->lock);
|
||||
rtems_debugger->lock = 0;
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: sema delete: %s\n",
|
||||
rtems_status_text(sc));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -333,52 +343,19 @@ rtems_debugger_connected(void)
|
||||
bool
|
||||
rtems_debugger_server_events_running(void)
|
||||
{
|
||||
bool running;
|
||||
rtems_debugger_lock();
|
||||
running = rtems_debugger->events_running;
|
||||
rtems_debugger_unlock();
|
||||
return running;
|
||||
return rtems_debugger->events_running;
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_server_events_wake(void)
|
||||
void
|
||||
rtems_debugger_server_events_signal(void)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
int r = 0;
|
||||
sc = rtems_event_send(rtems_debugger->events_task, RTEMS_EVENT_1);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: event send: %s\n",
|
||||
rtems_status_text(sc));
|
||||
errno = EIO;
|
||||
r = -1;
|
||||
}
|
||||
return r;
|
||||
_Condition_Signal(&rtems_debugger->server_cond);
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
rtems_debugger_server_events_wait(void)
|
||||
{
|
||||
rtems_event_set out = 0;
|
||||
rtems_status_code sc;
|
||||
int r = 0;
|
||||
rtems_debugger_unlock();
|
||||
while (true) {
|
||||
sc = rtems_event_receive(RTEMS_EVENT_1,
|
||||
RTEMS_EVENT_ALL | RTEMS_WAIT,
|
||||
RTEMS_NO_TIMEOUT,
|
||||
&out);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_debugger_printf("error: rtems-db: event receive: %s\n",
|
||||
rtems_status_text(sc));
|
||||
errno = EIO;
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
if (out == RTEMS_EVENT_1)
|
||||
break;
|
||||
}
|
||||
rtems_debugger_lock();
|
||||
return r;
|
||||
_Condition_Wait_recursive(&rtems_debugger->server_cond, &rtems_debugger->lock);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -432,8 +409,8 @@ rtems_debugger_remote_send(void)
|
||||
size_t i = 0;
|
||||
rtems_debugger_printf("rtems-db: put:%4zu: ", rtems_debugger->output_level);
|
||||
while (i < rtems_debugger->output_level)
|
||||
rtems_debugger_printf("%c", (char) rtems_debugger->output[i++]);
|
||||
rtems_debugger_printf("\n");
|
||||
rtems_debugger_clean_printf("%c", (char) rtems_debugger->output[i++]);
|
||||
rtems_debugger_clean_printf("\n");
|
||||
}
|
||||
|
||||
while (size) {
|
||||
@@ -533,14 +510,14 @@ rtems_debugger_remote_packet_in(void)
|
||||
}
|
||||
|
||||
if (rtems_debugger->remote_debug)
|
||||
rtems_debugger_printf("%c", c);
|
||||
rtems_debugger_clean_printf("%c", c);
|
||||
|
||||
switch (state) {
|
||||
case 'H':
|
||||
switch (c) {
|
||||
case '+':
|
||||
if (rtems_debugger->remote_debug) {
|
||||
rtems_debugger_printf(" [[ACK%s]]\n",
|
||||
rtems_debugger_clean_printf(" [[ACK%s]]\n",
|
||||
rtems_debugger->ack_pending ? "" : "?");
|
||||
remote_debug_header = true;
|
||||
}
|
||||
@@ -548,7 +525,7 @@ rtems_debugger_remote_packet_in(void)
|
||||
break;
|
||||
case '-':
|
||||
if (rtems_debugger->remote_debug) {
|
||||
rtems_debugger_printf(" [[NACK]]\n");
|
||||
rtems_debugger_clean_printf(" [[NACK]]\n");
|
||||
remote_debug_header = true;
|
||||
}
|
||||
/*
|
||||
@@ -561,13 +538,13 @@ rtems_debugger_remote_packet_in(void)
|
||||
csum = 0;
|
||||
in = 0;
|
||||
if (junk && rtems_debugger->remote_debug) {
|
||||
rtems_debugger_printf("\b [[junk dropped]]\nrtems-db: get: : $");
|
||||
rtems_debugger_clean_printf("\b [[junk dropped]]\nrtems-db: get: : $");
|
||||
remote_debug_header = false;
|
||||
}
|
||||
break;
|
||||
case '\x3':
|
||||
if (rtems_debugger->remote_debug)
|
||||
rtems_debugger_printf("^C [[BREAK]]\n");
|
||||
rtems_debugger_clean_printf("^C [[BREAK]]\n");
|
||||
rtems_debugger->ack_pending = false;
|
||||
rtems_debugger->input[0] = '^';
|
||||
rtems_debugger->input[1] = 'C';
|
||||
@@ -586,7 +563,7 @@ rtems_debugger_remote_packet_in(void)
|
||||
csum = 0;
|
||||
in = 0;
|
||||
if (rtems_debugger->remote_debug) {
|
||||
rtems_debugger_printf("\n");
|
||||
rtems_debugger_clean_printf("\n");
|
||||
remote_debug_header = true;
|
||||
}
|
||||
}
|
||||
@@ -613,12 +590,12 @@ rtems_debugger_remote_packet_in(void)
|
||||
if (csum == rx_csum) {
|
||||
state = 'F';
|
||||
if (rtems_debugger->remote_debug)
|
||||
rtems_debugger_printf("\n");
|
||||
rtems_debugger_clean_printf("\n");
|
||||
rtems_debugger_remote_send_ack();
|
||||
}
|
||||
else {
|
||||
if (rtems_debugger->remote_debug) {
|
||||
rtems_debugger_printf(" [[invalid checksum]]\n");
|
||||
rtems_debugger_clean_printf(" [[invalid checksum]]\n");
|
||||
remote_debug_header = true;
|
||||
rtems_debugger_remote_send_nack();
|
||||
}
|
||||
@@ -627,7 +604,7 @@ rtems_debugger_remote_packet_in(void)
|
||||
break;
|
||||
case 'F':
|
||||
if (rtems_debugger->remote_debug)
|
||||
rtems_debugger_printf(" [[extra data: 0x%02x]]", (int) c);
|
||||
rtems_debugger_clean_printf(" [[extra data: 0x%02x]]", (int) c);
|
||||
break;
|
||||
default:
|
||||
rtems_debugger_printf("rtems-db: bad state\n");
|
||||
@@ -810,6 +787,9 @@ remote_packet_dispatch(const rtems_debugger_packet* packet,
|
||||
if (strncmp(p->label,
|
||||
(const char*) &buffer[0],
|
||||
strlen(p->label)) == 0) {
|
||||
if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE_CMDS))
|
||||
rtems_debugger_printf("rtems-db: cmd: %s [%d] '%s'\n",
|
||||
p->label, size, (const char*) buffer);
|
||||
r = p->command(buffer, size);
|
||||
break;
|
||||
}
|
||||
@@ -904,7 +884,7 @@ remote_gq_thread_extra_info(uint8_t* buffer, int size)
|
||||
DB_UINT tid = 0;
|
||||
bool extended;
|
||||
extended = thread_id_decode(comma + 1, &pid, &tid);
|
||||
if (!extended || (extended && check_pid(pid))) {
|
||||
if (extended || check_pid(pid)) {
|
||||
int r;
|
||||
r = rtems_debugger_thread_find_index(tid);
|
||||
if (r >= 0) {
|
||||
@@ -954,7 +934,7 @@ remote_gq_supported(uint8_t* buffer, int size)
|
||||
p = strchr((const char*) buffer, ':');
|
||||
if (p != NULL)
|
||||
++p;
|
||||
while (p != NULL && p != '\0') {
|
||||
while (p != NULL && *p != '\0') {
|
||||
bool echo = false;
|
||||
char* sc;
|
||||
sc = strchr(p, ';');
|
||||
@@ -1022,8 +1002,8 @@ remote_gq_supported(uint8_t* buffer, int size)
|
||||
static int
|
||||
remote_gq_attached(uint8_t* buffer, int size)
|
||||
{
|
||||
const char const* response = "1";
|
||||
const char* colon = strchr((const char*) buffer, ':');
|
||||
const char* response = "1";
|
||||
const char* colon = strchr((const char*) buffer, ':');
|
||||
if (colon != NULL) {
|
||||
DB_UINT pid = hex_decode_uint((const uint8_t*) colon + 1);
|
||||
if ((pid_t) pid != rtems_debugger->pid)
|
||||
@@ -1061,7 +1041,7 @@ remote_general_query(uint8_t* buffer, int size)
|
||||
static int
|
||||
remote_gs_non_stop(uint8_t* buffer, int size)
|
||||
{
|
||||
const char const* response = r_E01;
|
||||
const char* response = r_E01;
|
||||
char* p = strchr((char*) buffer, ':');
|
||||
if (p != NULL) {
|
||||
++p;
|
||||
@@ -1173,6 +1153,7 @@ remote_v_continue(uint8_t* buffer, int size)
|
||||
if (r == 0)
|
||||
resume = true;
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
if (thread != NULL) {
|
||||
r = rtems_debugger_thread_step(thread);
|
||||
@@ -1202,6 +1183,7 @@ remote_v_continue(uint8_t* buffer, int size)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rtems_debugger_printf("rtems-db: vCont: unkown action: %c\n", action);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
@@ -1210,6 +1192,7 @@ remote_v_continue(uint8_t* buffer, int size)
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtems_debugger_printf("rtems-db: vCont: no colon\n");
|
||||
ok = false;
|
||||
}
|
||||
semi = strchr(semi + 1, ';');
|
||||
@@ -1257,8 +1240,8 @@ remote_v_packets(uint8_t* buffer, int size)
|
||||
static int
|
||||
remote_thread_select(uint8_t* buffer, int size)
|
||||
{
|
||||
const char const* response = r_OK;
|
||||
int* index = NULL;
|
||||
const char* response = r_OK;
|
||||
int* index = NULL;
|
||||
|
||||
if (buffer[1] == 'g')
|
||||
index = &rtems_debugger->threads->selector_gen;
|
||||
@@ -1299,10 +1282,10 @@ remote_thread_select(uint8_t* buffer, int size)
|
||||
static int
|
||||
remote_thread_alive(uint8_t* buffer, int size)
|
||||
{
|
||||
const char const* response = r_E01;
|
||||
DB_UINT pid = 0;
|
||||
DB_UINT tid = 0;
|
||||
bool extended;
|
||||
const char* response = r_E01;
|
||||
DB_UINT pid = 0;
|
||||
DB_UINT tid = 0;
|
||||
bool extended;
|
||||
extended = thread_id_decode((const char*) &buffer[1], &pid, &tid);
|
||||
if (!extended || (extended && check_pid(pid))) {
|
||||
int r;
|
||||
@@ -1423,7 +1406,7 @@ static int
|
||||
remote_write_reg(uint8_t* buffer, int size)
|
||||
{
|
||||
rtems_debugger_threads* threads = rtems_debugger->threads;
|
||||
const char const* response = r_E01;
|
||||
const char* response = r_E01;
|
||||
if (threads->selector_gen >= 0
|
||||
&& threads->selector_gen < (int) threads->current.level) {
|
||||
const char* equals;
|
||||
@@ -1487,9 +1470,9 @@ remote_read_memory(uint8_t* buffer, int size)
|
||||
static int
|
||||
remote_write_memory(uint8_t* buffer, int size)
|
||||
{
|
||||
const char const* response = r_E01;
|
||||
const char* comma;
|
||||
const char* colon;
|
||||
const char* response = r_E01;
|
||||
const char* comma;
|
||||
const char* colon;
|
||||
comma = strchr((const char*) buffer, ',');
|
||||
colon = strchr((const char*) buffer, ':');
|
||||
if (comma != NULL && colon != NULL) {
|
||||
@@ -1684,9 +1667,7 @@ rtems_debugger_events(rtems_task_argument arg)
|
||||
rtems_debugger_target_enable();
|
||||
|
||||
while (rtems_debugger_server_events_running()) {
|
||||
r = rtems_debugger_server_events_wait();
|
||||
if (r < 0)
|
||||
break;
|
||||
rtems_debugger_server_events_wait();
|
||||
if (!rtems_debugger_server_events_running())
|
||||
break;
|
||||
r = rtems_debugger_thread_system_suspend();
|
||||
@@ -1767,7 +1748,7 @@ rtems_debugger_session(void)
|
||||
}
|
||||
|
||||
rtems_debugger->events_running = false;
|
||||
rtems_debugger_server_events_wake();
|
||||
rtems_debugger_server_events_signal();
|
||||
|
||||
rtems_debugger_unlock();
|
||||
|
||||
@@ -1837,6 +1818,8 @@ rtems_debugger_create(const char* remote,
|
||||
rtems_debugger->pid = getpid();
|
||||
rtems_debugger->remote_debug = false;
|
||||
|
||||
rtems_chain_initialize_empty(&rtems_debugger->exception_threads);
|
||||
|
||||
rtems_debugger->remote = rtems_debugger_remote_find(remote);
|
||||
if (rtems_debugger->remote== NULL) {
|
||||
rtems_printf(printer, "error: rtems-db: remote not found: %s\n", remote);
|
||||
@@ -1851,6 +1834,7 @@ rtems_debugger_create(const char* remote,
|
||||
rtems_debugger->remote->name, strerror(errno));
|
||||
free(rtems_debugger);
|
||||
rtems_debugger = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1907,7 +1891,6 @@ rtems_debugger_main(rtems_task_argument arg)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
||||
rtems_debugger_lock();
|
||||
rtems_debugger->server_running = true;
|
||||
rtems_debugger->server_finished = false;
|
||||
@@ -1949,6 +1932,7 @@ rtems_debugger_start(const char* remote,
|
||||
rtems_debugger_lock();
|
||||
rtems_debugger->server_running = false;
|
||||
rtems_debugger->server_finished = true;
|
||||
_Condition_Initialize_named(&rtems_debugger->server_cond, "DBserver");
|
||||
rtems_debugger_unlock();
|
||||
|
||||
r = rtems_debugger_task_create("DBSs",
|
||||
|
||||
Reference in New Issue
Block a user