forked from Imagelibrary/rtems
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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -116,18 +116,13 @@
|
||||
#define RTEMS_DEBUGGER_NUMREGS 26
|
||||
|
||||
/*
|
||||
* Number of bytes per register.
|
||||
* Number of bytes per type of register.
|
||||
*/
|
||||
#define RTEMS_DEBUGGER_REGBYTES 4
|
||||
#define RTEMS_DEBUGGER_REG_BYTES 4
|
||||
#define RTEMS_DEBUGGER_FP_REG_BYTES 12
|
||||
|
||||
/*
|
||||
* Number of bytes of registers.
|
||||
*/
|
||||
#define RTEMS_DEBUGGER_NUMREGBYTES \
|
||||
(RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
|
||||
|
||||
/*
|
||||
* Debugger registers layout.
|
||||
* Debugger registers layout. See arm-core.xml in GDB source.
|
||||
*/
|
||||
#define REG_R0 0
|
||||
#define REG_R1 1
|
||||
@@ -145,8 +140,60 @@
|
||||
#define REG_SP 13
|
||||
#define REG_LR 14
|
||||
#define REG_PC 15
|
||||
#define REG_F0 16
|
||||
#define REG_F1 17
|
||||
#define REG_F2 18
|
||||
#define REG_F3 19
|
||||
#define REG_F4 20
|
||||
#define REG_F5 21
|
||||
#define REG_F6 22
|
||||
#define REG_F7 23
|
||||
#define REG_FPS 24
|
||||
#define REG_CPSR 25
|
||||
|
||||
/**
|
||||
* Register offset table with the total as the last entry.
|
||||
*
|
||||
* Check this table in gdb with the command:
|
||||
*
|
||||
* maint print registers
|
||||
*/
|
||||
static const size_t arm_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] =
|
||||
{
|
||||
0, /* REG_R0 4 uint32_t */
|
||||
4, /* REG_R1 4 uint32_t */
|
||||
8, /* REG_R2 4 uint32_t */
|
||||
12, /* REG_R3 4 uint32_t */
|
||||
16, /* REG_R4 4 uint32_t */
|
||||
20, /* REG_R5 4 uint32_t */
|
||||
24, /* REG_R6 4 uint32_t */
|
||||
28, /* REG_R7 4 uint32_t */
|
||||
32, /* REG_R8 4 uint32_t */
|
||||
36, /* REG_R9 4 uint32_t */
|
||||
40, /* REG_R10 4 uint32_t */
|
||||
44, /* REG_R11 4 uint32_t */
|
||||
48, /* REG_R12 4 uint32_t */
|
||||
52, /* REG_SP 4 *1 */
|
||||
56, /* REG_LR 4 uint32_t */
|
||||
60, /* REG_PC 4 *1 */
|
||||
64, /* REG_F0 12 _arm_ext */
|
||||
76, /* REG_F1 12 _arm_ext */
|
||||
88, /* REG_F2 12 _arm_ext */
|
||||
100, /* REG_F3 12 _arm_ext */
|
||||
112, /* REG_F4 12 _arm_ext */
|
||||
124, /* REG_F5 12 _arm_ext */
|
||||
136, /* REG_F6 12 _arm_ext */
|
||||
148, /* REG_F7 12 _arm_ext */
|
||||
160, /* REG_FPS 4 uint32_t */
|
||||
164, /* REG_CPSR 4 uint32_t */
|
||||
168 /* total size */
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of bytes of registers.
|
||||
*/
|
||||
#define RTEMS_DEBUGGER_NUMREGBYTES arm_reg_offsets[RTEMS_DEBUGGER_NUMREGS]
|
||||
|
||||
/**
|
||||
* The various status registers.
|
||||
*/
|
||||
@@ -235,8 +282,13 @@ target_printk(const char* format, ...)
|
||||
rtems_debugger_printk_unlock(&lock_context);
|
||||
va_end(ap);
|
||||
}
|
||||
#else
|
||||
#define target_printk(_fmt, ...)
|
||||
#define mode_labels(_m) NULL
|
||||
#endif
|
||||
|
||||
static const char*
|
||||
mode_label(int mode)
|
||||
arm_mode_label(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case 0x10:
|
||||
@@ -260,10 +312,6 @@ mode_label(int mode)
|
||||
}
|
||||
return "---";
|
||||
}
|
||||
#else
|
||||
#define target_printk(_fmt, ...)
|
||||
#define mode_labels(_m) NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CP register access.
|
||||
@@ -577,7 +625,7 @@ 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->reg_offset = arm_reg_offsets;
|
||||
target->breakpoint = &breakpoint[0];
|
||||
target->breakpoint_size = sizeof(breakpoint);
|
||||
return arm_debug_probe(target);
|
||||
@@ -590,7 +638,7 @@ target_exception(CPU_Exception_frame* frame)
|
||||
uint32_t ifsr = arm_cp15_get_instruction_fault_status();
|
||||
#endif
|
||||
|
||||
target_printk("[} frame = %08lx sig=%d vector=%x ifsr=%08lx pra=%08x\n",
|
||||
target_printk("[} frame = %08" PRIx32 " sig=%d vector=%x ifsr=%08" PRIx32 " pra=%08x\n",
|
||||
(uint32_t) frame,
|
||||
rtems_debugger_target_exception_to_signal(frame),
|
||||
frame->vector, ifsr, (intptr_t) frame->register_pc);
|
||||
@@ -632,7 +680,7 @@ target_exception(CPU_Exception_frame* frame)
|
||||
(FRAME_SR & (1 << 5)) != 0 ? 'T' : '-',
|
||||
((FRAME_SR >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR >> 10) & 0x1f),
|
||||
(FRAME_SR >> 16) & 0xf,
|
||||
FRAME_SR & 0x1f, mode_label(FRAME_SR & 0x1f));
|
||||
FRAME_SR & 0x1f, arm_mode_label(FRAME_SR & 0x1f));
|
||||
|
||||
arm_debug_break_clear();
|
||||
|
||||
@@ -652,7 +700,7 @@ target_exception(CPU_Exception_frame* frame)
|
||||
break;
|
||||
}
|
||||
|
||||
target_printk("[} resuming frame = %08lx PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
|
||||
target_printk("[} resuming frame = %08" PRIx32 " PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
|
||||
(uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR);
|
||||
}
|
||||
|
||||
@@ -986,6 +1034,34 @@ rtems_debugger_target_set_vectors(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
rtems_debugger_is_int_reg(size_t reg)
|
||||
{
|
||||
const size_t size = arm_reg_offsets[reg + 1] - arm_reg_offsets[reg];
|
||||
return size == RTEMS_DEBUGGER_REG_BYTES;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_debugger_set_int_reg(rtems_debugger_thread* thread,
|
||||
size_t reg,
|
||||
const uint32_t value)
|
||||
{
|
||||
const size_t offset = arm_reg_offsets[reg];
|
||||
/*
|
||||
* Use memcpy to avoid alignment issues.
|
||||
*/
|
||||
memcpy(&thread->registers[offset], &value, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static const uint32_t
|
||||
rtems_debugger_get_int_reg(rtems_debugger_thread* thread, size_t reg)
|
||||
{
|
||||
const size_t offset = arm_reg_offsets[reg];
|
||||
uint32_t value;
|
||||
memcpy(&value, &thread->registers[offset], sizeof(uint32_t));
|
||||
return value;
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_target_enable(void)
|
||||
{
|
||||
@@ -1028,11 +1104,14 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
|
||||
if (!rtems_debugger_thread_flag(thread,
|
||||
RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
|
||||
static const uint32_t good_address = (uint32_t) &good_address;
|
||||
uint32_t* regs = &thread->registers[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i)
|
||||
regs[i] = (uint32_t) &good_address;
|
||||
memset(&thread->registers[0], 0, RTEMS_DEBUGGER_NUMREGBYTES);
|
||||
|
||||
for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i) {
|
||||
if (rtems_debugger_is_int_reg(i))
|
||||
rtems_debugger_set_int_reg(thread, i, (uint32_t) &good_address);
|
||||
}
|
||||
|
||||
if (thread->frame) {
|
||||
CPU_Exception_frame* frame = thread->frame;
|
||||
@@ -1050,23 +1129,23 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
|
||||
thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
|
||||
}
|
||||
|
||||
regs[REG_R0] = frame->register_r0;
|
||||
regs[REG_R1] = frame->register_r1;
|
||||
regs[REG_R2] = frame->register_r2;
|
||||
regs[REG_R3] = frame->register_r3;
|
||||
regs[REG_R4] = frame->register_r4;
|
||||
regs[REG_R5] = frame->register_r5;
|
||||
regs[REG_R6] = frame->register_r6;
|
||||
regs[REG_R7] = frame->register_r7;
|
||||
regs[REG_R8] = frame->register_r8;
|
||||
regs[REG_R9] = frame->register_r9;
|
||||
regs[REG_R10] = frame->register_r10;
|
||||
regs[REG_R11] = frame->register_r11;
|
||||
regs[REG_R12] = frame->register_r12;
|
||||
regs[REG_SP] = frame->register_sp;
|
||||
regs[REG_LR] = (uint32_t) frame->register_lr;
|
||||
regs[REG_PC] = (uint32_t) frame->register_pc;
|
||||
regs[REG_CPSR] = FRAME_SR;
|
||||
rtems_debugger_set_int_reg(thread, REG_R0, frame->register_r0);
|
||||
rtems_debugger_set_int_reg(thread, REG_R1, frame->register_r1);
|
||||
rtems_debugger_set_int_reg(thread, REG_R2, frame->register_r2);
|
||||
rtems_debugger_set_int_reg(thread, REG_R3, frame->register_r3);
|
||||
rtems_debugger_set_int_reg(thread, REG_R4, frame->register_r4);
|
||||
rtems_debugger_set_int_reg(thread, REG_R5, frame->register_r5);
|
||||
rtems_debugger_set_int_reg(thread, REG_R6, frame->register_r6);
|
||||
rtems_debugger_set_int_reg(thread, REG_R7, frame->register_r7);
|
||||
rtems_debugger_set_int_reg(thread, REG_R8, frame->register_r8);
|
||||
rtems_debugger_set_int_reg(thread, REG_R9, frame->register_r9);
|
||||
rtems_debugger_set_int_reg(thread, REG_R10, frame->register_r10);
|
||||
rtems_debugger_set_int_reg(thread, REG_R11, frame->register_r11);
|
||||
rtems_debugger_set_int_reg(thread, REG_R12, frame->register_r12);
|
||||
rtems_debugger_set_int_reg(thread, REG_SP, frame->register_sp);
|
||||
rtems_debugger_set_int_reg(thread, REG_LR, (uint32_t) frame->register_lr);
|
||||
rtems_debugger_set_int_reg(thread, REG_PC, (uint32_t) frame->register_pc);
|
||||
rtems_debugger_set_int_reg(thread, REG_CPSR, FRAME_SR);
|
||||
/*
|
||||
* Get the signal from the frame.
|
||||
*/
|
||||
@@ -1074,29 +1153,29 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
|
||||
}
|
||||
else {
|
||||
#if defined(ARM_MULTILIB_ARCH_V4)
|
||||
regs[REG_R4] = thread->tcb->Registers.register_r4;
|
||||
regs[REG_R5] = thread->tcb->Registers.register_r5;
|
||||
regs[REG_R6] = thread->tcb->Registers.register_r6;
|
||||
regs[REG_R7] = thread->tcb->Registers.register_r7;
|
||||
regs[REG_R8] = thread->tcb->Registers.register_r8;
|
||||
regs[REG_R9] = thread->tcb->Registers.register_r9;
|
||||
regs[REG_R10] = thread->tcb->Registers.register_r10;
|
||||
regs[REG_R11] = thread->tcb->Registers.register_fp;
|
||||
regs[REG_LR] = (intptr_t) thread->tcb->Registers.register_lr;
|
||||
regs[REG_PC] = (intptr_t) thread->tcb->Registers.register_lr;
|
||||
regs[REG_SP] = (intptr_t) thread->tcb->Registers.register_sp;
|
||||
rtems_debugger_set_int_reg(thread, REG_R4, thread->tcb->Registers.register_r4);
|
||||
rtems_debugger_set_int_reg(thread, REG_R5, thread->tcb->Registers.register_r5);
|
||||
rtems_debugger_set_int_reg(thread, REG_R6, thread->tcb->Registers.register_r6);
|
||||
rtems_debugger_set_int_reg(thread, REG_R7, thread->tcb->Registers.register_r7);
|
||||
rtems_debugger_set_int_reg(thread, REG_R8, thread->tcb->Registers.register_r8);
|
||||
rtems_debugger_set_int_reg(thread, REG_R9, thread->tcb->Registers.register_r9);
|
||||
rtems_debugger_set_int_reg(thread, REG_R10, thread->tcb->Registers.register_r10);
|
||||
rtems_debugger_set_int_reg(thread, REG_R11, thread->tcb->Registers.register_fp);
|
||||
rtems_debugger_set_int_reg(thread, REG_LR, (intptr_t) thread->tcb->Registers.register_lr);
|
||||
rtems_debugger_set_int_reg(thread, REG_PC, (intptr_t) thread->tcb->Registers.register_lr);
|
||||
rtems_debugger_set_int_reg(thread, REG_SP, (intptr_t) thread->tcb->Registers.register_sp);
|
||||
#elif defined(ARM_MULTILIB_ARCH_V7M)
|
||||
regs[REG_R4] = thread->tcb->Registers.register_r4;
|
||||
regs[REG_R5] = thread->tcb->Registers.register_r5;
|
||||
regs[REG_R6] = thread->tcb->Registers.register_r6;
|
||||
regs[REG_R7] = thread->tcb->Registers.register_r7;
|
||||
regs[REG_R8] = thread->tcb->Registers.register_r8;
|
||||
regs[REG_R9] = thread->tcb->Registers.register_r9;
|
||||
regs[REG_R10] = thread->tcb->Registers.register_r10;
|
||||
regs[REG_R11] = thread->tcb->Registers.register_r11;
|
||||
regs[REG_LR] = (intptr_t) thread->tcb->Registers.register_lr;
|
||||
regs[REG_PC] = (intptr_t) thread->tcb->Registers.register_lr;
|
||||
regs[REG_SP] = (intptr_t) thread->tcb->Registers.register_sp;
|
||||
rtems_debugger_set_int_reg(thread, REG_R4, thread->tcb->Registers.register_r4);
|
||||
rtems_debugger_set_int_reg(thread, REG_R5, thread->tcb->Registers.register_r5);
|
||||
rtems_debugger_set_int_reg(thread, REG_R6, thread->tcb->Registers.register_r6);
|
||||
rtems_debugger_set_int_reg(thread, REG_R7, thread->tcb->Registers.register_r7);
|
||||
rtems_debugger_set_int_reg(thread, REG_R8, thread->tcb->Registers.register_r8);
|
||||
rtems_debugger_set_int_reg(thread, REG_R9, thread->tcb->Registers.register_r9);
|
||||
rtems_debugger_set_int_reg(thread, REG_R10, thread->tcb->Registers.register_r10);
|
||||
rtems_debugger_set_int_reg(thread, REG_R11, thread->tcb->Registers.register_r11);
|
||||
rtems_debugger_set_int_reg(thread, REG_LR, (intptr_t) thread->tcb->Registers.register_lr);
|
||||
rtems_debugger_set_int_reg(thread, REG_PC, (intptr_t) thread->tcb->Registers.register_lr);
|
||||
rtems_debugger_set_int_reg(thread, REG_SP, (intptr_t) thread->tcb->Registers.register_sp);
|
||||
#endif
|
||||
/*
|
||||
* Blocked threads have no signal.
|
||||
@@ -1116,8 +1195,6 @@ 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 exception threads. Do not touch the
|
||||
* registers for threads blocked in the context switcher.
|
||||
@@ -1125,23 +1202,23 @@ rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
|
||||
if (rtems_debugger_thread_flag(thread,
|
||||
RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
|
||||
CPU_Exception_frame* frame = thread->frame;
|
||||
frame->register_r0 = regs[REG_R0];
|
||||
frame->register_r1 = regs[REG_R1];
|
||||
frame->register_r2 = regs[REG_R2];
|
||||
frame->register_r3 = regs[REG_R3];
|
||||
frame->register_r4 = regs[REG_R4];
|
||||
frame->register_r5 = regs[REG_R5];
|
||||
frame->register_r6 = regs[REG_R6];
|
||||
frame->register_r7 = regs[REG_R7];
|
||||
frame->register_r8 = regs[REG_R8];
|
||||
frame->register_r9 = regs[REG_R9];
|
||||
frame->register_r10 = regs[REG_R10];
|
||||
frame->register_r11 = regs[REG_R11];
|
||||
frame->register_r12 = regs[REG_R12];
|
||||
frame->register_sp = regs[REG_SP];
|
||||
frame->register_lr = (void*) regs[REG_LR];
|
||||
frame->register_pc = (void*) regs[REG_PC];
|
||||
FRAME_SR = regs[REG_CPSR];
|
||||
frame->register_r0 = rtems_debugger_get_int_reg(thread, REG_R0);
|
||||
frame->register_r1 = rtems_debugger_get_int_reg(thread, REG_R1);
|
||||
frame->register_r2 = rtems_debugger_get_int_reg(thread, REG_R2);
|
||||
frame->register_r3 = rtems_debugger_get_int_reg(thread, REG_R3);
|
||||
frame->register_r4 = rtems_debugger_get_int_reg(thread, REG_R4);
|
||||
frame->register_r5 = rtems_debugger_get_int_reg(thread, REG_R5);
|
||||
frame->register_r6 = rtems_debugger_get_int_reg(thread, REG_R6);
|
||||
frame->register_r7 = rtems_debugger_get_int_reg(thread, REG_R7);
|
||||
frame->register_r8 = rtems_debugger_get_int_reg(thread, REG_R8);
|
||||
frame->register_r9 = rtems_debugger_get_int_reg(thread, REG_R9);
|
||||
frame->register_r10 = rtems_debugger_get_int_reg(thread, REG_R10);
|
||||
frame->register_r11 = rtems_debugger_get_int_reg(thread, REG_R11);
|
||||
frame->register_r12 = rtems_debugger_get_int_reg(thread, REG_R12);
|
||||
frame->register_sp = rtems_debugger_get_int_reg(thread, REG_SP);
|
||||
frame->register_lr = (void*) rtems_debugger_get_int_reg(thread, REG_LR);
|
||||
frame->register_pc = (void*) rtems_debugger_get_int_reg(thread, REG_PC);
|
||||
FRAME_SR = rtems_debugger_get_int_reg(thread, REG_CPSR);
|
||||
}
|
||||
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
|
||||
}
|
||||
@@ -1154,8 +1231,7 @@ 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_PC];
|
||||
return rtems_debugger_get_int_reg(thread, REG_PC);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1172,8 +1248,7 @@ 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_SP];
|
||||
return rtems_debugger_get_int_reg(thread, REG_SP);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1293,6 +1368,44 @@ rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
|
||||
return sig;
|
||||
}
|
||||
|
||||
void
|
||||
rtems_debugger_target_exception_print(CPU_Exception_frame* frame)
|
||||
{
|
||||
rtems_debugger_printf(" R0 = %08" PRIx32 " R1 = %08" PRIx32 \
|
||||
" R2 = %08" PRIx32 " R3 = %08" PRIx32 "\n",
|
||||
frame->register_r0, frame->register_r1,
|
||||
frame->register_r2, frame->register_r3);
|
||||
rtems_debugger_printf(" R4 = %08" PRIx32 " R5 = %08" PRIx32 \
|
||||
" R6 = %08" PRIx32 " R7 = %08" PRIx32 "\n",
|
||||
frame->register_r4, frame->register_r5,
|
||||
frame->register_r6, frame->register_r7);
|
||||
rtems_debugger_printf(" R8 = %08" PRIx32 " R9 = %08" PRIx32 \
|
||||
" R10 = %08" PRIx32 " R11 = %08" PRIx32 "\n",
|
||||
frame->register_r8, frame->register_r9,
|
||||
frame->register_r10, frame->register_r11);
|
||||
rtems_debugger_printf(" R12 = %08" PRIx32 " SP = %08" PRIx32 \
|
||||
" LR = %08" PRIxPTR " PC = %08" PRIxPTR "\n", \
|
||||
frame->register_r12, frame->register_sp,
|
||||
(intptr_t) frame->register_lr, (intptr_t) frame->register_pc);
|
||||
rtems_debugger_printf(" CPSR = %08" PRIx32 " %c%c%c%c%c%c%c%c%c%c%c" \
|
||||
" GE:%" PRIx32 " IT:%02" PRIx32 " M:%" PRIx32 " %s\n",
|
||||
FRAME_SR,
|
||||
(FRAME_SR & (1 << 31)) != 0 ? 'N' : '-',
|
||||
(FRAME_SR & (1 << 30)) != 0 ? 'Z' : '-',
|
||||
(FRAME_SR & (1 << 29)) != 0 ? 'C' : '-',
|
||||
(FRAME_SR & (1 << 28)) != 0 ? 'V' : '-',
|
||||
(FRAME_SR & (1 << 27)) != 0 ? 'Q' : '-',
|
||||
(FRAME_SR & (1 << 24)) != 0 ? 'J' : '-',
|
||||
(FRAME_SR & (1 << 9)) != 0 ? 'E' : '-',
|
||||
(FRAME_SR & (1 << 8)) != 0 ? 'A' : '-',
|
||||
(FRAME_SR & (1 << 7)) != 0 ? 'I' : '-',
|
||||
(FRAME_SR & (1 << 6)) != 0 ? 'F' : '-',
|
||||
(FRAME_SR & (1 << 5)) != 0 ? 'T' : '-',
|
||||
((FRAME_SR >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR >> 10) & 0x1f),
|
||||
(FRAME_SR >> 16) & 0xf,
|
||||
FRAME_SR & 0x1f, arm_mode_label(FRAME_SR & 0x1f));
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_target_hwbreak_insert(void)
|
||||
{
|
||||
|
||||
@@ -53,13 +53,7 @@
|
||||
/*
|
||||
* 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)
|
||||
#define RTEMS_DEBUGGER_REG_BYTES 4
|
||||
|
||||
/*
|
||||
* Debugger registers layout.
|
||||
@@ -83,6 +77,39 @@
|
||||
#define REG_FS 14
|
||||
#define REG_GS 15
|
||||
|
||||
/**
|
||||
* Register offset table with the total as the last entry.
|
||||
*
|
||||
* Check this table in gdb with the command:
|
||||
*
|
||||
* maint print registers
|
||||
*/
|
||||
static const size_t i386_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] =
|
||||
{
|
||||
0, /* REG_EAX 4 uint32_t */
|
||||
4, /* REG_ECX 4 uint32_t */
|
||||
8, /* REG_EDX 4 uint32_t */
|
||||
12, /* REG_EBX 4 uint32_t */
|
||||
16, /* REG_ESP 4 uint32_t */
|
||||
20, /* REG_EBP 4 uint32_t */
|
||||
24, /* REG_ESI 4 uint32_t */
|
||||
28, /* REG_EDI 4 uint32_t */
|
||||
32, /* REG_EIP 4 *1 */
|
||||
36, /* REG_EFLAGS 4 uint32_t */
|
||||
40, /* REG_CS 4 uint32_t */
|
||||
44, /* REG_SS 4 uint32_t */
|
||||
48, /* REG_DS 4 uint32_t */
|
||||
52, /* REG_ES 4 uint32_t */
|
||||
56, /* REG_FS 4 uint32_t */
|
||||
60, /* REG_GS 4 uint32_t */
|
||||
64 /* total size */
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of bytes of registers.
|
||||
*/
|
||||
#define RTEMS_DEBUGGER_NUMREGBYTES i386_reg_offsets[RTEMS_DEBUGGER_NUMREGS]
|
||||
|
||||
/**
|
||||
* The int 3 opcode.
|
||||
*/
|
||||
@@ -96,14 +123,34 @@ static const uint8_t breakpoint[1] = { TARGET_BKPT };
|
||||
#define GET_REG(_r, _v) asm volatile("pushl %%" #_r "; popl %0" : "=rm" (_v))
|
||||
|
||||
/*
|
||||
* Get a copy of a segment register.
|
||||
* A function to get a segment register.
|
||||
*/
|
||||
#define GET_SEG_REG(_r, _v) \
|
||||
do { \
|
||||
int _i; \
|
||||
GET_REG(_r, _i); \
|
||||
_v = _i & 0xffff; \
|
||||
} while (0)
|
||||
static inline uint32_t
|
||||
get_seg_reg(size_t reg)
|
||||
{
|
||||
int v = 0;
|
||||
switch (reg) {
|
||||
case REG_CS:
|
||||
GET_REG(CS, v);
|
||||
break;
|
||||
case REG_SS:
|
||||
GET_REG(SS, v);
|
||||
break;
|
||||
case REG_DS:
|
||||
GET_REG(DS, v);
|
||||
break;
|
||||
case REG_ES:
|
||||
GET_REG(ES, v);
|
||||
break;
|
||||
case REG_FS:
|
||||
GET_REG(FS, v);
|
||||
break;
|
||||
case REG_GS:
|
||||
GET_REG(GS, v);
|
||||
break;
|
||||
}
|
||||
return v & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Target lock.
|
||||
@@ -149,7 +196,7 @@ 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->reg_offset = i386_reg_offsets;
|
||||
target->breakpoint = &breakpoint[0];
|
||||
target->breakpoint_size = sizeof(breakpoint);
|
||||
return 0;
|
||||
@@ -158,7 +205,7 @@ rtems_debugger_target_configure(rtems_debugger_target* target)
|
||||
static void
|
||||
target_exception(CPU_Exception_frame* frame)
|
||||
{
|
||||
target_printk("[} frame = %08lx sig=%d (%lx)\n",
|
||||
target_printk("[} frame = %08" PRIx32 " sig=%d (%" PRIx32 ")\n",
|
||||
(uint32_t) frame,
|
||||
rtems_debugger_target_exception_to_signal(frame),
|
||||
frame->idtIndex);
|
||||
@@ -185,6 +232,34 @@ target_exception(CPU_Exception_frame* frame)
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
rtems_debugger_is_int_reg(size_t reg)
|
||||
{
|
||||
const size_t size = i386_reg_offsets[reg + 1] - i386_reg_offsets[reg];
|
||||
return size == RTEMS_DEBUGGER_REG_BYTES;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_debugger_set_int_reg(rtems_debugger_thread* thread,
|
||||
size_t reg,
|
||||
const uint32_t value)
|
||||
{
|
||||
const size_t offset = i386_reg_offsets[reg];
|
||||
/*
|
||||
* Use memcpy to avoid alignment issues.
|
||||
*/
|
||||
memcpy(&thread->registers[offset], &value, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static const uint32_t
|
||||
rtems_debugger_get_int_reg(rtems_debugger_thread* thread, size_t reg)
|
||||
{
|
||||
const size_t offset = i386_reg_offsets[reg];
|
||||
uint32_t value;
|
||||
memcpy(&value, &thread->registers[offset], sizeof(uint32_t));
|
||||
return value;
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_target_enable(void)
|
||||
{
|
||||
@@ -214,25 +289,27 @@ 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;
|
||||
for (i = 0; i < rtems_debugger_target_reg_num(); ++i) {
|
||||
if (rtems_debugger_is_int_reg(i))
|
||||
rtems_debugger_set_int_reg(thread, 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;
|
||||
|
||||
rtems_debugger_set_int_reg(thread, REG_EAX, frame->eax);
|
||||
rtems_debugger_set_int_reg(thread, REG_ECX, frame->ecx);
|
||||
rtems_debugger_set_int_reg(thread, REG_EDX, frame->edx);
|
||||
rtems_debugger_set_int_reg(thread, REG_EBX, frame->ebx);
|
||||
rtems_debugger_set_int_reg(thread, REG_ESP, frame->esp0);
|
||||
rtems_debugger_set_int_reg(thread, REG_EBP, frame->ebp);
|
||||
rtems_debugger_set_int_reg(thread, REG_ESI, frame->esi);
|
||||
rtems_debugger_set_int_reg(thread, REG_EDI, frame->edi);
|
||||
rtems_debugger_set_int_reg(thread, REG_EIP, frame->eip);
|
||||
rtems_debugger_set_int_reg(thread, REG_EFLAGS, frame->eflags);
|
||||
rtems_debugger_set_int_reg(thread, REG_CS, frame->cs);
|
||||
|
||||
/*
|
||||
* Get the signal from the frame.
|
||||
@@ -240,16 +317,16 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
|
||||
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;
|
||||
rtems_debugger_set_int_reg(thread, REG_EBX, thread->tcb->Registers.ebx);
|
||||
rtems_debugger_set_int_reg(thread, REG_ESI, thread->tcb->Registers.esi);
|
||||
rtems_debugger_set_int_reg(thread, REG_EDI, thread->tcb->Registers.edi);
|
||||
rtems_debugger_set_int_reg(thread, REG_EFLAGS, thread->tcb->Registers.eflags);
|
||||
rtems_debugger_set_int_reg(thread, REG_ESP, (intptr_t) thread->tcb->Registers.esp);
|
||||
rtems_debugger_set_int_reg(thread, REG_EBP, (intptr_t) thread->tcb->Registers.ebp);
|
||||
rtems_debugger_set_int_reg(thread, REG_EIP, *((DB_UINT*) thread->tcb->Registers.esp));
|
||||
rtems_debugger_set_int_reg(thread, REG_EAX, (intptr_t) thread);
|
||||
|
||||
GET_SEG_REG(CS, regs[REG_CS]);
|
||||
rtems_debugger_set_int_reg(thread, REG_CS, get_seg_reg(REG_CS));
|
||||
|
||||
/*
|
||||
* Blocked threads have no signal.
|
||||
@@ -257,11 +334,11 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
|
||||
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]);
|
||||
rtems_debugger_set_int_reg(thread, REG_SS, get_seg_reg(REG_SS));
|
||||
rtems_debugger_set_int_reg(thread, REG_DS, get_seg_reg(REG_DS));
|
||||
rtems_debugger_set_int_reg(thread, REG_ES, get_seg_reg(REG_ES));
|
||||
rtems_debugger_set_int_reg(thread, REG_FS, get_seg_reg(REG_FS));
|
||||
rtems_debugger_set_int_reg(thread, REG_GS, get_seg_reg(REG_GS));
|
||||
|
||||
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
|
||||
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
|
||||
@@ -275,8 +352,6 @@ 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.
|
||||
@@ -284,17 +359,17 @@ rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
|
||||
if (rtems_debugger_thread_flag(thread,
|
||||
RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
|
||||
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];
|
||||
frame->eax = rtems_debugger_get_int_reg(thread, REG_EAX);
|
||||
frame->ecx = rtems_debugger_get_int_reg(thread, REG_ECX);
|
||||
frame->edx = rtems_debugger_get_int_reg(thread, REG_EDX);
|
||||
frame->ebx = rtems_debugger_get_int_reg(thread, REG_EBX);
|
||||
frame->esp0 = rtems_debugger_get_int_reg(thread, REG_ESP);
|
||||
frame->ebp = rtems_debugger_get_int_reg(thread, REG_EBP);
|
||||
frame->esi = rtems_debugger_get_int_reg(thread, REG_ESI);
|
||||
frame->edi = rtems_debugger_get_int_reg(thread, REG_EDI);
|
||||
frame->eip = rtems_debugger_get_int_reg(thread, REG_EIP);
|
||||
frame->eflags = rtems_debugger_get_int_reg(thread, REG_EFLAGS);
|
||||
frame->cs = rtems_debugger_get_int_reg(thread, REG_CS);
|
||||
}
|
||||
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
|
||||
}
|
||||
@@ -307,8 +382,7 @@ 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 rtems_debugger_get_int_reg(thread, REG_EIP);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -325,8 +399,7 @@ 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 rtems_debugger_get_int_reg(thread, REG_ESP);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -400,6 +473,18 @@ rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
|
||||
return sig;
|
||||
}
|
||||
|
||||
void
|
||||
rtems_debugger_target_exception_print(CPU_Exception_frame* frame)
|
||||
{
|
||||
rtems_debugger_printf(" EAX = %" PRIx32 " EBX = %" PRIx32 \
|
||||
" ECX = %" PRIx32 " EDX = %" PRIx32 "\n",
|
||||
frame->eax, frame->ebx, frame->ecx, frame->edx);
|
||||
rtems_debugger_printf(" ESI = %" PRIx32 " EDI = %" PRIx32 \
|
||||
" EBP = %" PRIx32 " ESP = %" PRIx32 "\n",
|
||||
frame->esi, frame->edi, frame->ebp, frame->esp0);
|
||||
rtems_debugger_printf(" EIP = %" PRIx32"\n", frame->eip);
|
||||
}
|
||||
|
||||
int
|
||||
rtems_debugger_target_hwbreak_insert(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
|
||||
@@ -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, ...)
|
||||
{
|
||||
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);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
@@ -121,18 +115,14 @@ rtems_debugger_clean_printf(const char* format, ...)
|
||||
int
|
||||
rtems_debugger_printf(const char* format, ...)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
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