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:
Chris Johns
2017-07-17 09:53:11 +10:00
parent 2465c0130b
commit b2353ed924
15 changed files with 477 additions and 324 deletions

View File

@@ -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
@@ -40,12 +41,15 @@
#include "rtems-debugger-threads.h"
/**
* Frame signature.
* Exception local stack frame data to synchronise with the debugger
* server's events loop processor.
*/
#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 };
typedef struct {
rtems_chain_node node;
rtems_id id;
CPU_Exception_frame* frame;
rtems_rx_cond cond;
} rtems_debugger_exception;
#if TARGET_DEBUG
#include <rtems/bspIo.h>
@@ -53,9 +57,12 @@ static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
static void
target_printk(const char* format, ...)
{
rtems_interrupt_lock_context lock_context;
va_list ap;
va_start(ap, format);
rtems_debugger_printk_lock(&lock_context);
vprintk(format, ap);
rtems_debugger_printk_unlock(&lock_context);
va_end(ap);
}
#else
@@ -219,6 +226,11 @@ rtems_debugger_target_swbreak_insert(void)
if (target->breakpoint_size > 4)
memcpy(loc, &target->breakpoint[0], target->breakpoint_size);
else {
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: bp: in: %p %p %d %d %d\n",
loc, &target->breakpoint[0],
(int) target->breakpoint_size,
(int) i, (int) target->swbreaks.level);
switch (target->breakpoint_size) {
case 4:
loc[3] = target->breakpoint[3];
@@ -276,30 +288,22 @@ rtems_debugger_target_swbreak_remove(void)
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;
#if USE_THREAD_EXECUTING
Thread_Control* thread = _Thread_Executing;
#else
const Per_CPU_Control* cpu = _Per_CPU_Get_snapshot();
Thread_Control* thread = _Per_CPU_Get_executing(cpu);
#endif
rtems_id* excludes;
Thread_Control* thread = _Thread_Get_executing();
const rtems_id tid = thread->Object.id;
rtems_id* excludes;
DB_UINT pc;
const rtems_debugger_thread_stepper* stepper;
rtems_debugger_exception target_exception;
size_t i;
target_printk("[} tid:%08" PRIx32 ": thread:%08" PRIxPTR
" frame:%08" PRIxPTR "\n",
tid, (intptr_t) thread, (intptr_t) frame);
rtems_debugger_lock();
/*
* If the thread is the debugger recover.
*/
@@ -307,9 +311,11 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
if (rtems_debugger->target->memory_access) {
target_printk("[} server access fault\n");
rtems_debugger->target->memory_access = true;
rtems_debugger_unlock();
longjmp(rtems_debugger->target->access_return, -1);
}
target_printk("[} server exception\n");
rtems_debugger_unlock();
return rtems_debugger_target_exc_cascade;
}
@@ -327,6 +333,7 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
* swbreak's contents.
*/
target_printk("[} tid:%08lx: excluded\n", tid);
rtems_debugger_unlock();
return rtems_debugger_target_exc_cascade;
}
}
@@ -340,18 +347,39 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
stepper->thread->frame = frame;
rtems_debugger_target_thread_stepping(stepper->thread);
target_printk("[} tid:%08lx: stepping\n", tid);
rtems_debugger_unlock();
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.
* Initialise the target exception data and queue ready for the debugger
* server's event processor to handle.
*/
_Thread_Set_state(thread, STATES_DEBUGGER);
rtems_debugger_server_events_wake();
rtems_task_suspend(tid);
rtems_chain_initialize_node(&target_exception.node);
target_exception.frame = frame;
target_exception.id = tid;
_Condition_Initialize(&target_exception.cond);
rtems_chain_append_unprotected(&rtems_debugger->exception_threads,
&target_exception.node);
/*
* Signal the debug server's thread.
*/
rtems_debugger_server_events_signal();
/*
* Block on the exception thread's condition variable unlocking the
* debugger's mutex and letting the server's thread run.
*/
_Condition_Wait_recursive(&target_exception.cond, &rtems_debugger->lock);
/*
* Unlock the debugger's lock now the exception is resuming.
*/
rtems_debugger_unlock();
target_printk("[} tid:%08lx: resuming\n", tid);
@@ -363,31 +391,39 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
return rtems_debugger_target_exc_cascade;
}
int
rtems_debugger_target_set_exception_frame(rtems_debugger_thread* thread)
void
rtems_debugger_target_exception_thread(rtems_debugger_thread* thread)
{
int r = 0;
rtems_chain_node* node;
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->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
for (node = rtems_chain_first(&rtems_debugger->exception_threads);
!rtems_chain_is_tail(&rtems_debugger->exception_threads, node);
node = rtems_chain_next(node)) {
rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node;
if (target_exception->id == thread->id) {
thread->frame = target_exception->frame;
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
}
}
}
void
rtems_debugger_target_exception_thread_resume(rtems_debugger_thread* thread)
{
rtems_chain_node* node;
for (node = rtems_chain_first(&rtems_debugger->exception_threads);
!rtems_chain_is_tail(&rtems_debugger->exception_threads, node);
node = rtems_chain_next(node)) {
rtems_debugger_exception* target_exception = (rtems_debugger_exception*) node;
if (target_exception->id == thread->id) {
rtems_chain_extract(node);
thread->frame = NULL;
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION;
_Condition_Signal(&target_exception->cond);
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