libdebugger: ARM fixes for Cortex-A8 and ARM mode.

- Fix destorying the target and thread parts.
- Fix the ARM backend to support Cortex-A8 and ARM mode code.
- Use the DBGDSCR interrupt mask when single stepping.
- Use the DBGDSCR method of entry to debug mode to filter the
  execptions.
- Add support for BSPs to control the ARM backend.
This commit is contained in:
Chris Johns
2019-06-25 21:07:40 +10:00
parent 98d6792376
commit cb1e8497df
6 changed files with 728 additions and 245 deletions

View File

@@ -1882,6 +1882,7 @@ project_lib_LIBRARIES += libdebugger.a
libdebugger_a_SOURCES =
libdebugger_a_SOURCES += libdebugger/rtems-debugger-block.c
libdebugger_a_SOURCES += libdebugger/rtems-debugger-bsp.c
libdebugger_a_SOURCES += libdebugger/rtems-debugger-cmd.c
libdebugger_a_SOURCES += libdebugger/rtems-debugger-remote.c
libdebugger_a_SOURCES += libdebugger/rtems-debugger-remote-tcp.c

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2019 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Debugger BSP support.
*/
#ifndef _RTEMS_DEBUGGER_BSP_h
#define _RTEMS_DEBUGGER_BSP_h
#include <rtems/rtems-debugger.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* ARM
*/
/**
* Debug registers
*
* Return the debugger registers for you BSP if the SoC requires memory mapped
* registers and the DBGDRAR and DBGDSAR are not support or return 0. This
* function is provided in the ARM backend and declared weak.
*/
void* rtems_debugger_arm_debug_registers(void);
/**
* Configure the debug interface.
*
* Some ARM devices need special configurations to enable the debugging
* hardware. The device are often locked down for securty reasons and
* the debug hardware in the ARM needs to be enabled (asserting DBGEN).
*/
bool rtems_debugger_arm_debug_configure(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@@ -37,6 +37,8 @@
#include <rtems.h>
#include <rtems/score/threadimpl.h>
#include <rtems/debugger/rtems-debugger-bsp.h>
#include "rtems-debugger-target.h"
#include "rtems-debugger-threads.h"
@@ -76,12 +78,16 @@
*
* If the variant only supports thumb insturctions disable the support.
*/
#define ARM_SWITCH_REG uint32_t arm_switch_reg
#define ARM_SWITCH_REG_ASM [arm_switch_reg] "=&r" (arm_switch_reg)
#if !ARM_THUMB_ONLY && defined(__thumb__)
#define ARM_SWITCH_REG uint32_t arm_switch_reg
#define ARM_SWITCH_REG_ASM [arm_switch_reg] "=&r" (arm_switch_reg)
#define ARM_SWITCH_REG_ASM_L ARM_SWITCH_REG_ASM,
#define ASM_ARM_MODE ".align 2\nbx pc\n.arm\n"
#define ASM_THUMB_MODE "add %[arm_switch_reg], pc, #1\nbx %[arm_switch_reg]\n.thumb\n"
#else
#define ARM_SWITCH_REG
#define ARM_SWITCH_REG_ASM
#define ARM_SWITCH_REG_ASM_L
#define ASM_ARM_MODE
#define ASM_THUMB_MODE
#endif
@@ -198,13 +204,53 @@ static const size_t arm_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] =
* The various status registers.
*/
#if defined(ARM_MULTILIB_ARCH_V4)
#define FRAME_SR frame->register_cpsr
#define FRAME_SR(_frame) (_frame)->register_cpsr
#elif defined(ARM_MULTILIB_ARCH_V7M)
#define FRAME_SR frame->register_xpsr
#define FRAME_SR(_frame) (_frame)->register_xpsr
#else
#error ARM architecture is not supported.
#endif
/**
* Print the exception frame.
*/
#define EXC_FRAME_PRINT(_out, _prefix, _frame) \
do { \
_out(_prefix " 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); \
_out(_prefix " 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); \
_out(_prefix " 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); \
_out(_prefix " 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); \
_out(_prefix " 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), \
(FRAME_SR(_frame) & (1 << 31)) != 0 ? 'N' : '-', \
(FRAME_SR(_frame) & (1 << 30)) != 0 ? 'Z' : '-', \
(FRAME_SR(_frame) & (1 << 29)) != 0 ? 'C' : '-', \
(FRAME_SR(_frame) & (1 << 28)) != 0 ? 'V' : '-', \
(FRAME_SR(_frame) & (1 << 27)) != 0 ? 'Q' : '-', \
(FRAME_SR(_frame) & (1 << 24)) != 0 ? 'J' : '-', \
(FRAME_SR(_frame) & (1 << 9)) != 0 ? 'E' : '-', \
(FRAME_SR(_frame) & (1 << 8)) != 0 ? 'A' : '-', \
(FRAME_SR(_frame) & (1 << 7)) != 0 ? 'I' : '-', \
(FRAME_SR(_frame) & (1 << 6)) != 0 ? 'F' : '-', \
(FRAME_SR(_frame) & (1 << 5)) != 0 ? 'T' : '-', \
(FRAME_SR(_frame) >> 16) & 0xf, \
((FRAME_SR(_frame) >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR(_frame) >> 10) & 0x1f), \
FRAME_SR(_frame) & 0x1f, arm_mode_label(FRAME_SR(_frame) & 0x1f)); \
} while (0)
/**
* The breakpoint.
*/
@@ -219,6 +265,18 @@ static const size_t arm_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] =
*/
RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
/**
* An exception offset is added to the return address of the PC on an
* exception's stack frame. The PC needs to be adjusted.
*/
static const size_t exc_offsets[2][5] =
{
/* ARM undef_ins sup call pref abt data abt */
{ 0, 4, 0, 4, 8 },
/* TMB undef_ins sup call pref abt data abt */
{ 0, 2, 0, 4, 8 }
};
/**
* Is a session active?
*/
@@ -228,7 +286,9 @@ static bool debug_session_active;
* ARM debug hardware.
*/
static int debug_version;
static int debug_revision;;
static void* debug_registers;
static int debug_revision;
static bool debug_disable_ints;
static int hw_breakpoints;
static int hw_watchpoints;
@@ -266,6 +326,26 @@ typedef struct
static arm_debug_hwbreak hw_breaks[ARM_HW_BREAKPOINT_MAX];
//static arm_debug_hwbreak hw_watches[ARM_HW_WATCHPOINT_MAX];
/*
* Method of entry (MOE) to debug mode. Bits [5:2] of DBGDSCR.
*/
#define ARM_HW_DSCR_MOE_HALT_REQUEST (0x0)
#define ARM_HW_DSCR_MOE_BREAKPOINT_EVENT (0x1)
#define ARM_HW_DSCR_MOE_ASYNC_WATCHPOINT (0x2)
#define ARM_HW_DSCR_MOE_BREAKPOINT_INSTR (0x3)
#define ARM_HW_DSCR_MOE_EXTERNAL (0x4)
#define ARM_HW_DSCR_MOE_VECTOR_CATCH_EVENT (0x5)
#define ARM_HW_DSCR_MOE_OS_UNLOCK_EVENT (0x8)
#define ARM_HW_DSCR_MOE_SYNC_WATCHPOINT (0xa)
/*
* Use to locally probe and catch exceptions when accessinf suspect addresses.
*/
static void __attribute__((naked)) arm_debug_unlock_abort(void);
/*
* Target debugging support. Use this to debug the backend.
*/
#if TARGET_DEBUG
void rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context);
void rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context);
@@ -313,6 +393,34 @@ arm_mode_label(int mode)
return "---";
}
#if TARGET_DEBUG
static const char*
arm_moe_label(uint32_t moe)
{
switch (moe) {
case ARM_HW_DSCR_MOE_HALT_REQUEST:
return "HLT";
case ARM_HW_DSCR_MOE_BREAKPOINT_EVENT:
return "BPE";
case ARM_HW_DSCR_MOE_ASYNC_WATCHPOINT:
return "AWP";
case ARM_HW_DSCR_MOE_BREAKPOINT_INSTR:
return "BPI";
case ARM_HW_DSCR_MOE_EXTERNAL:
return "EXT";
case ARM_HW_DSCR_MOE_VECTOR_CATCH_EVENT:
return "VCE";
case ARM_HW_DSCR_MOE_OS_UNLOCK_EVENT:
return "OUL";
case ARM_HW_DSCR_MOE_SYNC_WATCHPOINT:
return "SWP";
default:
break;
}
return "RSV";
}
#endif
/*
* CP register access.
*/
@@ -337,10 +445,16 @@ arm_mode_label(int mode)
ASM_ARM_MODE \
ARM_CP_INSTR(mrc, _cp, _op1, val, _CRn, _CRm, _op2) \
ASM_THUMB_MODE \
: ARM_SWITCH_REG_ASM, \
: ARM_SWITCH_REG_ASM_L \
[val] "=&r" (_val)); \
} while (0)
/*
* CP14 register access.
*
* The registers can be access via the core or they can be memory-mapped.
*/
/*
* Read and write a CP14 register.
*
@@ -367,6 +481,167 @@ arm_mode_label(int mode)
#define ARM_CP15_READ(_val, _op1, _CRn, _CRm, _op2) \
ARM_CP_READ(15, _op1, _val, _CRn, _CRm, _op2)
/*
* Read and write a memory mapped debug register. The register number is a word
* offset from the base address.
*/
#define ARM_MMAP_ADDR(reg) (((volatile uint32_t*) debug_registers) + (reg))
#define ARM_MMAP_WRITE(reg, val) *ARM_MMAP_ADDR(reg) = (val); _ARM_Data_synchronization_barrier()
#define ARM_MMAP_READ(reg) *ARM_MMAP_ADDR(reg)
static bool
arm_debug_authentication(uint32_t dbgauthstatus)
{
bool granted = (dbgauthstatus & (1 << 0)) != 0;
rtems_debugger_printf("rtems-db: arm debug: authentication: %s " \
"(%s %s %s %s %s %s %s %s)\n",
granted ? "granted" : "denied",
(dbgauthstatus & (1 << 0)) == 0 ? "-" : "NSE",
(dbgauthstatus & (1 << 1)) == 0 ? "-" : "NSI",
(dbgauthstatus & (1 << 2)) == 0 ? "-" : "NSNE",
(dbgauthstatus & (1 << 3)) == 0 ? "-" : "NSNI",
(dbgauthstatus & (1 << 4)) == 0 ? "-" : "SE",
(dbgauthstatus & (1 << 5)) == 0 ? "-" : "SI",
(dbgauthstatus & (1 << 6)) == 0 ? "-" : "SNE",
(dbgauthstatus & (1 << 7)) == 0 ? "-" : "SNI");
return granted;
}
static int
arm_debug_cp14_enable(rtems_debugger_target* target)
{
uint32_t val;
ARM_CP14_READ(val, 7, 14, 6);
if (!arm_debug_authentication(val))
return -1;
ARM_CP14_READ(val, 0, 1, 0);
if ((val & (1 << 15)) == 0) {
switch (debug_version) {
case 1:
case 2:
ARM_CP14_WRITE(val | (1 << 15), 0, 1, 0);
break;
case 3:
case 5:
default:
ARM_CP14_WRITE(val | (1 << 15), 0, 2, 2);
break;
case 4:
rtems_debugger_printf("rtems-db: arm debug: no cp14 access with version 4\n");
return -1;
}
ARM_CP14_READ(val, 0, 1, 0);
if ((val & (1 << 15)) == 0) {
rtems_debugger_printf("rtems-db: arm debug: cannot enter monitor mode\n");
errno = EIO;
return -1;
}
}
rtems_debugger_printf("rtems-db: arm debug: using cp14 register access\n");
return 0;
}
/*
* The write access to the software unlock register can cause an abort. Absorb
* it.
*/
static jmp_buf unlock_abort_jmpbuf;
static size_t arm_debug_retries;
static int
arm_debug_mmap_enable(rtems_debugger_target* target, uint32_t dbgdidr)
{
uint32_t rom;
uint32_t val;
void* abort_handler;
int rc = -1;
/*
* File scope as setjmp/longjmp effect the local stack variables.
*/
arm_debug_retries = 5;
/*
* The DBGDSAR is a signed offset from DBGDRAR. Both need to be
* valid for the debug register address to be valid. Currently there
* is no support to decode a ROM table.
*/
ARM_CP14_READ(rom, 1, 0, 0);
if ((rom & 3) == 3) {
ARM_CP14_READ(val, 2, 0, 0);
if ((val & 3) == 3 ) {
debug_registers = (void*) ((rom & ~3) + ((int32_t) (val & ~3)));
}
}
if (debug_registers == NULL) {
debug_registers = rtems_debugger_arm_debug_registers();
if (debug_registers == NULL) {
rtems_debugger_printf("rtems-db: arm debug: no valid register map\n");
return -1;
}
}
/*
* Make sure the memory mapped registers return the same ID.
*/
if (ARM_MMAP_READ(0) != dbgdidr) {
debug_registers = NULL;
rtems_debugger_printf("rtems-db: arm debug: debug reg map not verified: " \
"0x%08x\n", ARM_MMAP_READ(0));
return -1;
}
if (!arm_debug_authentication(ARM_MMAP_READ(1006)))
return -1;
#if ARM_CP15
abort_handler =
arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT,
arm_debug_unlock_abort);
#endif
while (arm_debug_retries-- > 0) {
if (setjmp(unlock_abort_jmpbuf) == 0) {
/*
* If there is a software lock and it is locked unlock it.
*
* On the TI am335x this can cause a data abort which we catch and retry
* which seems to make the debug hardware work.
*/
if (ARM_MMAP_READ(1005) == 3) {
ARM_MMAP_WRITE(1004, 0xC5ACCE55);
}
/*
* Are we already in debug mode?
*/
val = ARM_MMAP_READ(34);
if ((val & (1 << 15)) == 0) {
rtems_debugger_printf("rtems-db: arm debug: enable debug mode\n");
val = ARM_MMAP_READ(34);
ARM_MMAP_WRITE(34, ARM_MMAP_READ(34) | (1 << 15));
arm_debug_retries = 0;
}
}
}
#if ARM_CP15
arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT, abort_handler);
#endif
if (arm_debug_retries > 0) {
rtems_debugger_printf("rtems-db: arm debug: using debug register access\n");
rc = 0;
}
else {
rtems_debugger_printf("rtems-db: arm debug: cannot enter debug mode\n");
}
val = ARM_MMAP_READ(1006);
return rc;
}
static int
arm_debug_probe(rtems_debugger_target* target)
{
@@ -380,7 +655,21 @@ arm_debug_probe(rtems_debugger_target* target)
"ARMv7 [v7, baseline CP14 registers]",
"ARMv7 [v7.1]"
};
int rc = -1;
#if ARM_CP15
ARM_CP15_READ(val, 0, 0, 0, 0);
rtems_debugger_printf("rtems-db: arm core: Architecture: %d Variant: %d " \
"Implementor: %d Part Number: %d Revision: %d\n",
(val >> 16) & ((1 << (19 - 16 + 1)) - 1),
(val >> 20) & ((1 << (23 - 20 + 1)) - 1),
(val >> 24) & ((1 << (31 - 24 + 1)) - 1),
(val >> 4) & ((1 << (15 - 4 + 1)) - 1),
(val >> 0) & ((1 << ( 3 - 0 + 1)) - 1));
#endif
ARM_CP14_READ(val, 0, 0, 0);
debug_version = ID_VALUE(val, 19, 16);
if (debug_version < 1 || debug_version > 5) {
rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) not supported\n",
@@ -388,35 +677,36 @@ arm_debug_probe(rtems_debugger_target* target)
errno = EIO;
return -1;
}
vl = labels[debug_version - 1];
debug_revision = ID_VALUE(val, 3, 0);
hw_breakpoints = ID_VALUE(val, 27, 24);
hw_watchpoints = ID_VALUE(val, 31, 28);
rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) %s breakpoints:%d watchpoints:%d\n",
rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) %s " \
"breakpoints:%d watchpoints:%d\n",
debug_version, debug_revision, vl,
hw_breakpoints, hw_watchpoints);
ARM_CP14_READ(val, 0, 1, 0);
if ((val & (1 << 15)) == 0) {
if (!rtems_debugger_arm_debug_configure())
return -1;
switch (debug_version) {
case 1:
case 2:
ARM_CP14_WRITE(val | (1 << 15), 0, 1, 0);
break;
case 3:
case 4:
case 5:
default:
ARM_CP14_WRITE(val | (1 << 15), 0, 2, 2);
rc = arm_debug_mmap_enable(target, val);
if (rc != 0)
rc = arm_debug_cp14_enable(target);
break;
case 4:
rc = arm_debug_mmap_enable(target, val);
break;
}
ARM_CP14_READ(val, 0, 1, 0);
if ((val & (1 << 15)) == 0) {
rtems_debugger_printf("rtems-db: arm debug: cannot enter monitor mode\n");
errno = EIO;
return -1;
}
}
return 0;
return rc;
}
static inline void
@@ -435,6 +725,11 @@ arm_debug_break_setup(arm_debug_hwbreak* bp,
static void
arm_debug_break_write_control(int bp, uint32_t control)
{
if (bp < 15) {
if (debug_registers != NULL) {
ARM_MMAP_WRITE(80 + bp, control);
}
else {
switch (bp) {
case 0:
ARM_CP14_WRITE(control, 0, 0, 5);
@@ -485,11 +780,18 @@ arm_debug_break_write_control(int bp, uint32_t control)
ARM_CP14_WRITE(control, 0, 15, 5);
break;
}
}
}
}
static void
arm_debug_break_write_value(int bp, uint32_t value)
{
if (bp < 15) {
if (debug_registers != NULL) {
ARM_MMAP_WRITE(64 + bp, value);
}
else {
switch (bp) {
case 0:
ARM_CP14_WRITE(value, 0, 0, 4);
@@ -540,6 +842,59 @@ arm_debug_break_write_value(int bp, uint32_t value)
ARM_CP14_WRITE(value, 0, 15, 4);
break;
}
}
}
}
static uint32_t
arm_debug_dbgdscr_read(void)
{
uint32_t val;
if (debug_registers != NULL) {
val = ARM_MMAP_READ(34);
}
else {
ARM_CP14_READ(val, 0, 1, 0);
}
return val;
}
static void
arm_debug_dbgdscr_write(uint32_t val)
{
if (debug_registers != NULL) {
ARM_MMAP_WRITE(34, val);
}
else {
ARM_CP14_WRITE(val, 0, 1, 0);
}
}
static uint32_t
arm_debug_method_of_entry(void)
{
return (arm_debug_dbgdscr_read() >> 2) & 0xf;
}
static void
arm_debug_disable_interrupts(void)
{
debug_disable_ints = true;
}
static void
arm_debug_commit_interrupt_disable(void)
{
if (debug_disable_ints) {
arm_debug_dbgdscr_write(arm_debug_dbgdscr_read() | (1 << 11));
debug_disable_ints = false;
}
}
static void
arm_debug_enable_interrupts(void)
{
arm_debug_dbgdscr_write(arm_debug_dbgdscr_read() & ~(1 << 11));
}
static void
@@ -559,7 +914,9 @@ arm_debug_break_clear(void)
static inline void
arm_debug_set_context_id(const uint32_t id)
{
#if ARM_CP15
ARM_CP15_WRITE(id, 0, 13, 0, 1);
#endif
}
/*
@@ -604,6 +961,21 @@ arm_debug_break_unload(void)
rtems_interrupt_lock_release(&target_lock, &lock_context);
}
static void
arm_debug_break_dump(void)
{
#if TARGET_DEBUG
arm_debug_hwbreak* bp = &hw_breaks[0];
int i;
for (i = 0; i < hw_breakpoints; ++i, ++bp) {
if (bp->enabled) {
target_printk("[} bp: %d: control: %08x addr: %08x\n",
i, bp->control, bp->value);
}
}
#endif
}
#if NOT_USED_BUT_KEEPING
static size_t
arm_debug_break_length(void* pc)
@@ -631,57 +1003,63 @@ rtems_debugger_target_configure(rtems_debugger_target* target)
return arm_debug_probe(target);
}
static void
target_print_frame(CPU_Exception_frame* frame)
{
EXC_FRAME_PRINT(target_printk, "[} ", frame);
}
static const size_t
target_exc_offset(CPU_Exception_frame* frame)
{
size_t thumb = (FRAME_SR(frame) & (1 << 5)) == 0 ? 0 : 1;
return exc_offsets[thumb][frame->vector];
}
static void
target_exception(CPU_Exception_frame* frame)
{
#if TARGET_DEBUG
uint32_t ifsr = arm_cp15_get_instruction_fault_status();
#if ARM_CP15
const uint32_t ifsr = arm_cp15_get_instruction_fault_status();
#else
const uint32_t ifsr = 0;
#endif
const uint32_t mvector = frame->vector;
const uint32_t dbgdscr = arm_debug_dbgdscr_read();
#endif
target_printk("[} frame = %08" PRIx32 " sig=%d vector=%x ifsr=%08" PRIx32 " pra=%08x\n",
const uint32_t moe = arm_debug_method_of_entry();
const size_t exc_offset = target_exc_offset(frame);
switch (moe){
case ARM_HW_DSCR_MOE_BREAKPOINT_EVENT:
case ARM_HW_DSCR_MOE_BREAKPOINT_INSTR:
case ARM_HW_DSCR_MOE_ASYNC_WATCHPOINT:
case ARM_HW_DSCR_MOE_SYNC_WATCHPOINT:
frame->vector = 2;
break;
case ARM_HW_DSCR_MOE_HALT_REQUEST:
case ARM_HW_DSCR_MOE_EXTERNAL:
case ARM_HW_DSCR_MOE_VECTOR_CATCH_EVENT:
case ARM_HW_DSCR_MOE_OS_UNLOCK_EVENT:
default:
break;
}
target_printk("[} > frame = %08" PRIx32 \
" sig=%d vector=%u (%u) dbgdscr=%08" PRIx32 " moe=%s" \
" ifsr=%08" PRIx32 " pra=%08x\n",
(uint32_t) frame,
rtems_debugger_target_exception_to_signal(frame),
frame->vector, ifsr, (intptr_t) frame->register_pc);
frame->vector, mvector, dbgdscr, arm_moe_label(moe),
ifsr, (intptr_t) frame->register_pc);
if ((FRAME_SR & (1 << 5)) == 0)
frame->register_pc = (void*) ((intptr_t) frame->register_pc - 8);
else
frame->register_pc = (void*) ((intptr_t) frame->register_pc - 4);
frame->register_pc = (void*) ((intptr_t) frame->register_pc - exc_offset);
target_printk("[} 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);
target_printk("[} 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);
target_printk("[} 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);
target_printk("[} 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);
target_printk("[} 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));
target_print_frame(frame);
arm_debug_enable_interrupts();
arm_debug_break_clear();
if (!debug_session_active)
@@ -692,7 +1070,6 @@ target_exception(CPU_Exception_frame* frame)
default:
break;
case rtems_debugger_target_exc_step:
FRAME_SR |= CPSR_INTS_MASK;
break;
case rtems_debugger_target_exc_cascade:
target_printk("rtems-db: unhandled exception: cascading\n");
@@ -700,8 +1077,11 @@ target_exception(CPU_Exception_frame* frame)
break;
}
target_printk("[} resuming frame = %08" PRIx32 " PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
(uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR);
target_printk("[} < resuming frame = %08" PRIx32 \
" PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
(uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR(frame));
target_print_frame(frame);
arm_debug_break_dump();
}
/**
@@ -777,6 +1157,8 @@ target_exception(CPU_Exception_frame* frame)
#define EXCEPTION_ENTRY_FPU(frame_fpu_size)
#endif /* ARM_MULTILIB_VFP */
#define ARM_CLEAR_THUMB_MODE "bic r1, r1, %[psr_t]\n" /* clear thumb */
#define EXCEPTION_ENTRY_THREAD_V4(_frame) \
__asm__ volatile( \
ASM_ARM_MODE \
@@ -785,7 +1167,7 @@ target_exception(CPU_Exception_frame* frame)
"add r0, sp, %[r0_r12_size]\n" /* get the sp in the frame */ \
"mrs r1, spsr\n" /* get the saved sr */ \
"mov r6, r1\n" /* stash it for later */ \
"bic r1, r1, %[psr_t]\n" /* clear thumb mode, not sure? */ \
ARM_CLEAR_THUMB_MODE /* clear thumb mode */ \
"orr r1, r1, %[psr_i]\n" /* mask irqs */ \
"mrs r2, cpsr\n" /* get the current sr */ \
"str r2, [sp, %[frame_cpsr]]\n" /* save for exc return */ \
@@ -818,7 +1200,7 @@ target_exception(CPU_Exception_frame* frame)
"bic r1, r1, %[psr_i]\n" /* clear irq mask, debug checks */ \
"msr cpsr, r1\n" /* restore the state with irq mask clear */ \
ASM_THUMB_MODE \
: ARM_SWITCH_REG_ASM, \
: ARM_SWITCH_REG_ASM_L \
[o_frame] "=r" (_frame) \
: [psr_t] "i" (ARM_PSR_T), \
[psr_i] "i" (ARM_PSR_I), \
@@ -879,8 +1261,9 @@ target_exception(CPU_Exception_frame* frame)
"strb r1, [r4, #1]!\n" /* put the byte */ \
"cmp r3, r4\n" /* the end? */ \
"bne 1b\n" \
"mov r0, %[i_frame]\n" /* get the frame */ \
"add r1, r0, %[r0_r12_size]\n" /* get the sp in the frame */ \
"ldm r1, {r3-r6}\n" /* recover from the frame */ \
"ldm r1, {r3-r6}\n" /* recover sp, lr, pc, cpsr */ \
"orr r1, r6, %[psr_i]\n" /* get the thread's psr and mask irqs */ \
"msr cpsr, r1\n" /* switch to user mode */ \
"mov sp, r3\n" /* set the stack pointer */ \
@@ -930,6 +1313,19 @@ target_exception(CPU_Exception_frame* frame)
#error ARM architecture is not supported.
#endif
/*
* This is used to catch faulting accesses.
*/
static void __attribute__((naked))
arm_debug_unlock_abort(void)
{
CPU_Exception_frame* frame;
ARM_SWITCH_REG;
EXCEPTION_ENTRY_EXC();
EXCEPTION_ENTRY_THREAD(frame);
longjmp(unlock_abort_jmpbuf, -1);
}
static void __attribute__((naked))
target_exception_undefined_instruction(void)
{
@@ -937,10 +1333,12 @@ target_exception_undefined_instruction(void)
ARM_SWITCH_REG;
EXCEPTION_ENTRY_EXC();
arm_debug_break_unload();
arm_debug_enable_interrupts();
EXCEPTION_ENTRY_THREAD(frame);
frame->vector = 1;
target_exception(frame);
EXCEPTION_EXIT_THREAD(frame);
arm_debug_commit_interrupt_disable();
arm_debug_break_load();
EXCEPTION_EXIT_EXC();
}
@@ -951,16 +1349,19 @@ target_exception_supervisor_call(void)
CPU_Exception_frame* frame;
ARM_SWITCH_REG;
/*
* The PC offset needs to be review so we move past a svc instruction. This
* can then used as a user breakpoint. The issue is this exception is used by
* the BKPT instruction in the prefetch abort handler to signal a TRAP.
* The PC offset needs to be reviewed so we move past a svc
* instruction. This can then be used as a user breakpoint. The issue is
* this exception is used by the BKPT instruction in the prefetch abort
* handler to signal a TRAP.
*/
EXCEPTION_ENTRY_EXC();
arm_debug_break_unload();
arm_debug_enable_interrupts();
EXCEPTION_ENTRY_THREAD(frame);
frame->vector = 2;
target_exception(frame);
EXCEPTION_EXIT_THREAD(frame);
arm_debug_commit_interrupt_disable();
arm_debug_break_load();
EXCEPTION_EXIT_EXC();
}
@@ -972,17 +1373,12 @@ target_exception_prefetch_abort(void)
ARM_SWITCH_REG;
EXCEPTION_ENTRY_EXC();
arm_debug_break_unload();
arm_debug_enable_interrupts();
EXCEPTION_ENTRY_THREAD(frame);
#if ARM_CP15
if ((arm_cp15_get_instruction_fault_status() & 0x1f) == 0x02)
frame->vector = 2;
else
frame->vector = 3;
#else
frame->vector = 3;
#endif
target_exception(frame);
EXCEPTION_EXIT_THREAD(frame);
arm_debug_commit_interrupt_disable();
arm_debug_break_load();
EXCEPTION_EXIT_EXC();
}
@@ -994,10 +1390,12 @@ target_exception_data_abort(void)
ARM_SWITCH_REG;
EXCEPTION_ENTRY_EXC();
arm_debug_break_unload();
arm_debug_enable_interrupts();
EXCEPTION_ENTRY_THREAD(frame);
frame->vector = 4;
target_exception(frame);
EXCEPTION_EXIT_THREAD(frame);
arm_debug_commit_interrupt_disable();
arm_debug_break_load();
EXCEPTION_EXIT_EXC();
}
@@ -1013,16 +1411,23 @@ extern char bsp_section_text_begin[];
extern char bsp_section_text_end[];
static void
rtems_debugger_target_set_vectors(void)
rtems_debugger_target_set_mmu(void)
{
void* text_begin;
void* text_end;
text_begin = &bsp_section_text_begin[0];
text_end = &bsp_section_text_end[0];
target_printk("[} MMU edit: text_begin: %p text_end: %p\n",
text_begin, text_end);
text_section_flags =
arm_cp15_set_translation_table_entries(text_begin,
text_end,
ARMV7_MMU_DATA_READ_WRITE_CACHED);
}
static void
rtems_debugger_target_set_vectors(void)
{
arm_cp15_set_exception_handler(ARM_EXCEPTION_UNDEF,
target_exception_undefined_instruction);
arm_cp15_set_exception_handler(ARM_EXCEPTION_SWI,
@@ -1048,6 +1453,11 @@ rtems_debugger_target_set_vectors(void)
(void) pa;
(void) da;
}
static void
rtems_debugger_target_set_mmu(void)
{
}
#endif
static bool
@@ -1086,6 +1496,7 @@ rtems_debugger_target_enable(void)
arm_debug_break_unload();
arm_debug_break_clear();
rtems_interrupt_lock_acquire(&target_lock, &lock_context);
rtems_debugger_target_set_mmu();
rtems_debugger_target_set_vectors();
rtems_interrupt_lock_release(&target_lock, &lock_context);
return 0;
@@ -1136,13 +1547,13 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
* Assume interrupts are not masked and if masked set them to the saved
* value.
*/
FRAME_SR &= ~CPSR_INTS_MASK;
FRAME_SR(frame) &= ~CPSR_INTS_MASK;
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED)) {
FRAME_SR |=
FRAME_SR(frame) |=
(thread->flags >> RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE) & CPSR_INTS_MASK;
thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
}
rtems_debugger_set_int_reg(thread, REG_R0, frame->register_r0);
@@ -1161,7 +1572,7 @@ rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
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);
rtems_debugger_set_int_reg(thread, REG_CPSR, FRAME_SR(frame));
/*
* Get the signal from the frame.
*/
@@ -1234,7 +1645,7 @@ rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
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);
FRAME_SR(frame) = rtems_debugger_get_int_reg(thread, REG_CPSR);
}
thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
}
@@ -1285,10 +1696,12 @@ rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
*/
CPU_Exception_frame* frame = thread->frame;
arm_debug_hwbreak* bp = &hw_breaks[0];
target_printk("[} stepping: %s\n", bp->enabled ? "yes" : "no");
if (!bp->enabled) {
const uint32_t addr = (intptr_t) frame->register_pc;
const bool thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false;
const bool thumb = (FRAME_SR(frame) & (1 << 5)) != 0 ? true : false;
uint32_t bas;
bp->enabled = true;
@@ -1333,21 +1746,7 @@ rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
bas,
ARM_HW_BP_PRIV_PL0_SUP_SYS);
/*
* Save the interrupt state before stepping if set.
*/
#if ARM_PSR_HAS_INT_MASK
if ((FRAME_SR & CPSR_INTS_MASK) != 0) {
uint32_t int_state;
int_state =
(frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE;
thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state;
}
/*
* Mask the interrupt when stepping.
*/
FRAME_SR |= CPSR_INTS_MASK;
#endif
arm_debug_disable_interrupts();
}
}
return 0;
@@ -1387,39 +1786,7 @@ rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
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));
EXC_FRAME_PRINT(rtems_debugger_printf, "", frame);
}
int

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/debugger/rtems-debugger-bsp.h>
void* rtems_debugger_arm_debug_registers(void) __attribute__ ((weak));
bool rtems_debugger_arm_debug_configure(void) __attribute__ ((weak));
void*
rtems_debugger_arm_debug_registers(void)
{
return NULL;
}
bool
rtems_debugger_arm_debug_configure(void)
{
return true;
}

View File

@@ -1704,13 +1704,13 @@ rtems_debugger_session(void)
r = rtems_debugger_target_create();
if (r < 0) {
rtems_debugger_thread_destroy();
rtems_debugger_unlock();
return r;
}
r = rtems_debugger_thread_create();
if (r < 0) {
rtems_debugger_target_destroy();
rtems_debugger_unlock();
return r;
}
@@ -1725,8 +1725,8 @@ rtems_debugger_session(void)
0,
&rtems_debugger->events_task);
if (r < 0) {
rtems_debugger_target_destroy();
rtems_debugger_thread_destroy();
rtems_debugger_target_destroy();
rtems_debugger_unlock();
return r;
}

View File

@@ -362,6 +362,7 @@ rtems_debugger_thread_system_resume(bool detaching)
rtems_debugger_thread* thread = &current[i];
rtems_status_code sc;
int rr;
bool has_exception;
/*
* Check if resuming, which can be continuing, a step, or stepping a
* range.
@@ -380,11 +381,13 @@ rtems_debugger_thread_system_resume(bool detaching)
r = rr;
}
}
has_exception =
rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION);
if (rtems_debugger_verbose())
rtems_debugger_printf("rtems-db: sys: : resume: 0x%08" PRIx32 "\n",
thread->id);
if (rtems_debugger_thread_flag(thread,
RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
rtems_debugger_printf("rtems-db: sys: : resume: 0x%08" PRIx32 " %c\n",
thread->id, has_exception ? 'E' : ' ');
if (has_exception) {
rtems_debugger_target_exception_thread_resume(thread);
} else {
sc = rtems_task_resume(thread->id);