libdebugger: Use an offset table to format GDB g packets.

Adding support for a register offset table lets FPU registers
be supported if added to the backend.

Closes #3733.
This commit is contained in:
Chris Johns
2019-04-09 15:02:24 +10:00
parent 8a8b95aa1d
commit 2c09b71faf
8 changed files with 478 additions and 215 deletions
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
* Copyright (c) 2016-2019 Chris Johns <chrisj@rtems.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -176,6 +176,11 @@ extern void rtems_debugger_unlock(void);
*/
extern bool rtems_debugger_server_running(void);
/**
* Signel a server crash.
*/
extern void rtems_debugger_server_crash(void);
/**
* Get the remote handle from the debugger.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+40 -37
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
* Copyright (c) 2016-2019 Chris Johns <chrisj@rtems.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,9 +25,9 @@
*/
#define RTEMS_DEBUGGER_VERBOSE_LOCK 0
#define RTEMS_DEBUGGER_PRINT_PRINTK 1
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
@@ -84,9 +84,7 @@ 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)
@@ -103,17 +101,13 @@ rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context)
int
rtems_debugger_clean_printf(const char* format, ...)
{
int len;
va_list ap;
rtems_interrupt_lock_context lock_context;
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);
rtems_debugger_printk_lock(&lock_context);
len = vprintk(format, ap);
rtems_debugger_printk_unlock(&lock_context);
va_end(ap);
return len;
}
@@ -121,18 +115,14 @@ rtems_debugger_clean_printf(const char* format, ...)
int
rtems_debugger_printf(const char* format, ...)
{
int len;
va_list ap;
rtems_interrupt_lock_context lock_context;
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);
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);
rtems_debugger_printk_lock(&lock_context);
printk("[CPU:%d] ", (int) _SMP_Get_current_processor ());
len = vprintk(format, ap);
rtems_debugger_printk_unlock(&lock_context);
va_end(ap);
return len;
}
@@ -897,7 +887,7 @@ remote_gq_thread_extra_info(uint8_t* buffer, int size)
current = rtems_debugger_thread_current(threads);
thread = &current[r];
l = snprintf(buf, sizeof(buf),
"%4s (%08lx), ", thread->name, thread->id);
"%4s (%08" PRIx32 "), ", thread->name, thread->id);
remote_packet_out_append_hex((const uint8_t*) buf, l);
l = snprintf(buf, sizeof(buf),
"priority(c:%3d r:%3d), ",
@@ -1330,7 +1320,7 @@ remote_read_general_regs(uint8_t* buffer, int size)
if (r >= 0) {
remote_packet_out_reset();
r = remote_packet_out_append_hex((const uint8_t*) &thread->registers[0],
rtems_debugger_target_reg_size());
rtems_debugger_target_reg_table_size());
if (r >= 0)
ok = true;
}
@@ -1345,12 +1335,12 @@ static int
remote_write_general_regs(uint8_t* buffer, int size)
{
rtems_debugger_threads* threads = rtems_debugger->threads;
size_t reg_size = rtems_debugger_target_reg_size();
size_t reg_table_size = rtems_debugger_target_reg_table_size();
bool ok = false;
int r;
if (threads->selector_gen >= 0 &&
threads->selector_gen < (int) threads->current.level &&
((size - 1) / 2) == (int) reg_size) {
((size - 1) / 2) == (int) reg_table_size) {
rtems_debugger_thread* current;
rtems_debugger_thread* thread;
current = rtems_debugger_thread_current(threads);
@@ -1359,7 +1349,7 @@ remote_write_general_regs(uint8_t* buffer, int size)
if (r >= 0) {
r = rtems_debugger_remote_packet_in_hex((uint8_t*) &thread->registers[0],
(const char*) &buffer[1],
reg_size);
reg_table_size);
if (r >= 0) {
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
ok = true;
@@ -1388,9 +1378,11 @@ remote_read_reg(uint8_t* buffer, int size)
thread = &current[threads->selector_gen];
r = rtems_debugger_target_read_regs(thread);
if (r >= 0) {
const uint8_t* addr = (const uint8_t*) &thread->registers[reg];
const size_t reg_size = rtems_debugger_target_reg_size(reg);
const size_t reg_offset = rtems_debugger_target_reg_offset(reg);
const uint8_t* addr = &thread->registers[reg_offset];
remote_packet_out_reset();
r = remote_packet_out_append_hex(addr, sizeof(thread->registers[0]));
r = remote_packet_out_append_hex(addr, reg_size);
if (r >= 0)
ok = true;
}
@@ -1421,10 +1413,10 @@ remote_write_reg(uint8_t* buffer, int size)
thread = &current[threads->selector_gen];
r = rtems_debugger_target_read_regs(thread);
if (r >= 0) {
uint8_t* addr = (uint8_t*) &thread->registers[reg];
r = rtems_debugger_remote_packet_in_hex(addr,
equals + 1,
sizeof(thread->registers[reg]));
const size_t reg_size = rtems_debugger_target_reg_size(reg);
const size_t reg_offset = rtems_debugger_target_reg_offset(reg);
uint8_t* addr = &thread->registers[reg_offset];
r = rtems_debugger_remote_packet_in_hex(addr, equals + 1, reg_size);
if (r == 0) {
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
response = r_OK;
@@ -1505,7 +1497,7 @@ remote_single_step(uint8_t* buffer, int size)
rtems_debugger_thread* current;
char vCont_s[32];
current = rtems_debugger_thread_current(threads);
snprintf(vCont_s, sizeof(vCont_s), "vCont;s:p1.%08lx;c:p1.-1",
snprintf(vCont_s, sizeof(vCont_s), "vCont;s:p1.%08" PRIx32 ";c:p1.-1",
current[threads->selector_cont].id);
return remote_v_continue((uint8_t*) vCont_s, strlen(vCont_s));
}
@@ -1668,6 +1660,8 @@ rtems_debugger_events(rtems_task_argument arg)
while (rtems_debugger_server_events_running()) {
rtems_debugger_server_events_wait();
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: event woken\n");
if (!rtems_debugger_server_events_running())
break;
r = rtems_debugger_thread_system_suspend();
@@ -1949,6 +1943,15 @@ rtems_debugger_start(const char* remote,
return 0;
}
void
rtems_debugger_server_crash(void)
{
rtems_debugger_lock();
rtems_debugger->server_running = false;
rtems_debugger_unlock();
rtems_debugger->remote->end(rtems_debugger->remote);
}
int
rtems_debugger_stop(void)
{
+51 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
* Copyright (c) 2016-2019 Chris Johns <chrisj@rtems.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,16 +134,36 @@ rtems_debugger_target_capabilities(void)
size_t
rtems_debugger_target_reg_num(void)
{
if (rtems_debugger->target != NULL)
return rtems_debugger->target->reg_num;
rtems_debugger_target* target = rtems_debugger->target;
if (target != NULL)
return target->reg_num;
return 0;
}
size_t
rtems_debugger_target_reg_size(void)
rtems_debugger_target_reg_size(size_t reg)
{
if (rtems_debugger->target != NULL)
return rtems_debugger->target->reg_num * rtems_debugger->target->reg_size;
rtems_debugger_target* target = rtems_debugger->target;
if (target != NULL && reg < target->reg_num)
return target->reg_offset[reg + 1] - target->reg_offset[reg];
return 0;
}
size_t
rtems_debugger_target_reg_offset(size_t reg)
{
rtems_debugger_target* target = rtems_debugger->target;
if (target != NULL && reg < target->reg_num)
return target->reg_offset[reg];
return 0;
}
size_t
rtems_debugger_target_reg_table_size(void)
{
rtems_debugger_target* target = rtems_debugger->target;
if (target != NULL)
return target->reg_offset[target->reg_num];
return 0;
}
@@ -305,17 +325,23 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
rtems_debugger_lock();
/*
* If the thread is the debugger recover.
* If the thread is in the debugger recover. If the access is from gdb
* continue else shutdown and let the user know.
*/
if (tid == rtems_debugger->server_task) {
if (rtems_debugger->target->memory_access) {
target_printk("[} server access fault\n");
rtems_debugger->target->memory_access = true;
rtems_debugger_unlock();
if (tid == rtems_debugger->server_task ||
tid == rtems_debugger->events_task) {
bool memory_access = rtems_debugger_target_is_memory_access();
rtems_debugger_unlock();
/*
* Has GDB has asked us to write to an address?
*/
if (memory_access) {
target_printk("[} server fault: memory access\n");
longjmp(rtems_debugger->target->access_return, -1);
}
target_printk("[} server exception\n");
rtems_debugger_unlock();
rtems_debugger_printf("rtems-db: server exception (report)\n");
rtems_debugger_target_exception_print(frame);
rtems_debugger_server_crash();
return rtems_debugger_target_exc_cascade;
}
@@ -332,7 +358,7 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
* the contents of the instruction, step then return the
* swbreak's contents.
*/
target_printk("[} tid:%08lx: excluded\n", tid);
target_printk("[} tid:%08" PRIx32 ": excluded\n", tid);
rtems_debugger_unlock();
return rtems_debugger_target_exc_cascade;
}
@@ -346,12 +372,12 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
if (stepper != NULL) {
stepper->thread->frame = frame;
rtems_debugger_target_thread_stepping(stepper->thread);
target_printk("[} tid:%08lx: stepping\n", tid);
target_printk("[} tid:%08" PRIx32 ": stepping\n", tid);
rtems_debugger_unlock();
return rtems_debugger_target_exc_step;
}
target_printk("[} tid:%08lx: suspending\n", tid);
target_printk("[} tid:%08" PRIx32 ": suspending\n", tid);
/*
* Initialise the target exception data and queue ready for the debugger
@@ -381,12 +407,12 @@ rtems_debugger_target_exception(CPU_Exception_frame* frame)
*/
rtems_debugger_unlock();
target_printk("[} tid:%08lx: resuming\n", tid);
target_printk("[} tid:%08" PRIx32 ": resuming\n", tid);
return rtems_debugger_target_exc_consumed;
}
target_printk("[} cascade, in interrupt\n");
rtems_debugger_printf("rtems-db: exception in an interrupt, cascading\n");
return rtems_debugger_target_exc_cascade;
}
@@ -439,3 +465,9 @@ rtems_debugger_target_end_memory_access(void)
{
rtems_debugger->target->memory_access = false;
}
bool
rtems_debugger_target_is_memory_access(void)
{
return rtems_debugger->target->memory_access;
}
+27 -3
View File
@@ -85,11 +85,15 @@ typedef struct rtems_debugger_target_swbreak {
/**
* The target data.
*
* reg_offset: Table of size_t offset of a register in the register
* table. The table has one more entry than reg_num where
* the last entry is the size of the register table.
*/
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 size_t* reg_offset; /*<< The reg offsettable, len = reg_num + 1. */
const uint8_t* breakpoint; /*<< The breakpoint instruction(s). */
size_t breakpoint_size; /*<< The breakpoint size. */
rtems_debugger_block swbreaks; /*<< The software breakpoint block. */
@@ -133,9 +137,19 @@ extern uint32_t rtems_debugger_target_capabilities(void);
extern size_t rtems_debugger_target_reg_num(void);
/**
* Return the size of the regisers in bytes.
* Return the offset of a register in the register table.
*/
extern size_t rtems_debugger_target_reg_size(void);
extern size_t rtems_debugger_target_reg_size(size_t reg);
/**
* Return the offset of a register in the register table.
*/
extern size_t rtems_debugger_target_reg_offset(size_t reg);
/**
* Return the size of register table.
*/
extern size_t rtems_debugger_target_reg_table_size(void);
/**
* Read the regosters.
@@ -177,6 +191,11 @@ extern int rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread);
*/
extern int rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame);
/**
* Print the target exception registers.
*/
extern void rtems_debugger_target_exception_print(CPU_Exception_frame* frame);
/**
* Software breakpoints. These are also referred to as memory breakpoints.
*/
@@ -245,6 +264,11 @@ extern int rtems_debugger_target_start_memory_access(void);
*/
extern void rtems_debugger_target_end_memory_access(void);
/**
* Is this a target memory access?
*/
extern bool rtems_debugger_target_is_memory_access(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+8 -7
View File
@@ -25,6 +25,7 @@
*/
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
@@ -85,7 +86,7 @@ rtems_debugger_thread_create(void)
r = rtems_debugger_block_create(&threads->registers,
RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
rtems_debugger_target_reg_size());
rtems_debugger_target_reg_table_size());
if (r < 0) {
rtems_debugger_thread_free(threads);
free(threads);
@@ -209,7 +210,7 @@ snapshot_thread(rtems_tcb* tcb, void* arg)
}
else {
rtems_debugger_thread* current;
DB_UINT* registers;
uint8_t* registers;
rtems_debugger_thread* thread;
int r;
@@ -229,7 +230,7 @@ snapshot_thread(rtems_tcb* tcb, void* arg)
thread = &current[threads->current.level++];
thread->registers =
&registers[threads->registers.level++ * rtems_debugger_target_reg_num()];
&registers[threads->registers.level++ * rtems_debugger_target_reg_table_size()];
thread->tcb = tcb;
thread->id = id;
@@ -262,7 +263,7 @@ snapshot_thread(rtems_tcb* tcb, void* arg)
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",
rtems_debugger_printf("error: rtems-db: thread: suspend: %08" PRIx32 ": %s\n",
id, rtems_status_text(sc));
r = -1;
}
@@ -274,7 +275,7 @@ snapshot_thread(rtems_tcb* tcb, void* arg)
rtems_debugger_target_read_regs(thread);
if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE))
rtems_debugger_printf("rtems-db: sys: thd: %08lx: signal: %d\n",
rtems_debugger_printf("rtems-db: sys: thd: %08" PRIx32 ": signal: %d\n",
id, thread->signal);
/*
@@ -380,7 +381,7 @@ rtems_debugger_thread_system_resume(bool detaching)
}
}
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: sys: : resume: 0x%08lx\n",
rtems_debugger_printf("rtems-db: sys: : resume: 0x%08" PRIx32 "\n",
thread->id);
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
@@ -388,7 +389,7 @@ rtems_debugger_thread_system_resume(bool detaching)
} else {
sc = rtems_task_resume(thread->id);
if (sc != RTEMS_SUCCESSFUL) {
rtems_debugger_printf("error: rtems-db: thread: resume: %08lx: %s\n",
rtems_debugger_printf("error: rtems-db: thread: resume: %08" PRIx32 ": %s\n",
thread->id, rtems_status_text(sc));
}
}
+2 -2
View File
@@ -90,7 +90,7 @@ typedef struct rtems_debugger_thread
Thread_Control* tcb;
rtems_id id;
int cpu;
DB_UINT* registers;
uint8_t* registers;
int signal;
void* frame;
} rtems_debugger_thread;
@@ -234,7 +234,7 @@ rtems_debugger_thread_current(rtems_debugger_threads* threads)
/**
* Get the registers.
*/
static inline DB_UINT*
static inline uint8_t*
rtems_debugger_thread_registers(rtems_debugger_threads* threads)
{
return threads->registers.block;