mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-10-06 10:59:48 +08:00
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:
@@ -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
@@ -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 = ¤t[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 = ¤t[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 = ¤t[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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 = ¤t[threads->current.level++];
|
||||
thread->registers =
|
||||
®isters[threads->registers.level++ * rtems_debugger_target_reg_num()];
|
||||
®isters[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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user