From fd67814e06a734cd0d78274d61fc04c7af79b5fc Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 23 Apr 2018 12:06:14 +0200 Subject: bsps: Move GDB stubs to bsps This patch is a part of the BSP source reorganization. Update #3285. --- c/src/lib/libbsp/lm32/shared/gdbstub/README | 82 -- c/src/lib/libbsp/lm32/shared/gdbstub/gdb_if.h | 125 --- c/src/lib/libbsp/lm32/shared/gdbstub/lm32-debug.S | 338 -------- c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c | 977 ---------------------- 4 files changed, 1522 deletions(-) delete mode 100644 c/src/lib/libbsp/lm32/shared/gdbstub/README delete mode 100644 c/src/lib/libbsp/lm32/shared/gdbstub/gdb_if.h delete mode 100644 c/src/lib/libbsp/lm32/shared/gdbstub/lm32-debug.S delete mode 100644 c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c (limited to 'c/src/lib/libbsp/lm32') diff --git a/c/src/lib/libbsp/lm32/shared/gdbstub/README b/c/src/lib/libbsp/lm32/shared/gdbstub/README deleted file mode 100644 index bbd1f53a9d..0000000000 --- a/c/src/lib/libbsp/lm32/shared/gdbstub/README +++ /dev/null @@ -1,82 +0,0 @@ -This is a thread-aware gdb stub for the lm32 architecture. It has to be -linked with the application, which should be debugged. The application has -to call 'lm32_gdb_stub_install' to setup the stub. - The stub remaps _all_ h/w exceptions to an own code (lm32-debug.S), which -saves all the registers, calls the gdb stub and restores the registers again. - The interrupt exceptions gets handled in a special way. Because we remapped -this exception, we need to do - - the same as the original one (in cpu_asm.S), - - and, as we might use an ISR for breaking into a running application with - gdb, we need to save all registers as well. To be backward compatible - the missing callee saved registers gets appended to CPU_Interrupt_frame. - There is a mapping in 'gdb_handle_break' for that. - -To use this gdb stub, your bsp has to provide the following functions: - - void gdb_put_debug_char(char c) - Puts the given charater c to the debug console output. The function can - block until the character can be written to the output buffer. - - - char gdb_get_debug_char(void) - Returns the character in the input buffer of the debug console. If no one - is availabe, the function must block. - - - void gdb_console_init() - This function can be used to initialize the debug console. Additionally, - it should set up the ISR for the debug console to call the function - 'gdb_handle_break', which is provided by the gdb stub and enable the - interrupt for a break symbol on the debug serial port. If no ISR is - provided, you won't be able to interrupt a running application. - - - void gdb_ack_irq() - If an ISR is used, this function is used to acknowledge the interrupt. - -NOTE: the stub don't skip a hardcoded 'break' in the code. So you have to - set the PC an instruction further in the debugger (set $pc += 4). - -NOTE2: make sure you have the following CFLAGS set: - -mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled - -msign-extend-enabled - Without the hardware support, it is done in software. Unfortunately, the - stub also uses some shifts and multiplies. If you step through your code, - there will be a chance that a breakpoint is set to one of that functions, - which then causes an endless loop. - - -EXAMPLES - - char gdb_get_debug_char(void) - { - /* Wait until there is a byte in RXTX */ - while (!(uartread(LM32_UART_LSR) & LM32_UART_LSR_DR)); - - return (char) uartread(LM32_UART_RBR); - } - - void gdb_put_debug_char(char c) - { - /* Wait until RXTX is empty. */ - while (!(uartread(LM32_UART_LSR) & LM32_UART_LSR_THRE)); - uartwrite(LM32_UART_RBR, c); - } - - extern void gdb_handle_break( - rtems_vector_number vector, - CPU_Interrupt_frame *frame - ); - void gdb_console_init() - { - rtems_isr_entry old; - - /* enable interrupts */ - uartwrite(LM32_UART_IER, 1); - - rtems_interrupt_catch((rtems_isr_entry) gdb_handle_break, DEBUG_UART_IRQ, - &old); - lm32_interrupt_unmask(1 << DEBUG_UART_IRQ); - } - - void gdb_ack_irq() - { - lm32_interrupt_ack(1 << DEBUG_UART_IRQ); - } - diff --git a/c/src/lib/libbsp/lm32/shared/gdbstub/gdb_if.h b/c/src/lib/libbsp/lm32/shared/gdbstub/gdb_if.h deleted file mode 100644 index 6df9c8e921..0000000000 --- a/c/src/lib/libbsp/lm32/shared/gdbstub/gdb_if.h +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @file - * @ingroup lm32_gdb - * @brief definition of the interface between the stub and gdb - */ - -/* - * gdb_if.h - definition of the interface between the stub and gdb - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * The following software is offered for use in the public domain. - * There is no warranty with regard to this software or its performance - * and the user must accept the software "AS IS" with all faults. - * - * THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH - * REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * @defgroup lm32_gdb LM32 GDB Interface - * @ingroup lm32_shared - * @brief Definition of the interface between the stub and gdb, - * @{ - */ - -#ifndef _GDB_IF_H -#define _GDB_IF_H - -/** @brief Max number of threads in qM response */ -#define QM_MAX_THREADS (20) - -struct rtems_gdb_stub_thread_info { - char display[256]; - char name[256]; - char more_display[256]; -}; - -/* - * Prototypes - */ - -int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len); - -char* mem2hstr(char *buf, const unsigned char *mem, int count); -int hstr2mem(unsigned char *mem, const char *buf, int count); -void set_mem_err(void); -unsigned char get_byte(const unsigned char *ptr); -void set_byte(unsigned char *ptr, int val); -char* thread2vhstr(char *buf, int thread); -char* thread2fhstr(char *buf, int thread); -const char* fhstr2thread(const char *buf, int *thread); -const char* vhstr2thread(const char *buf, int *thread); -char* int2fhstr(char *buf, int val); -char* int2vhstr(char *buf, int vali); -const char* fhstr2int(const char *buf, int *ival); -const char* vhstr2int(const char *buf, int *ival); -int hstr2byte(const char *buf, int *bval); -int hstr2nibble(const char *buf, int *nibble); - -Thread_Control *rtems_gdb_index_to_stub_id(int); -int rtems_gdb_stub_thread_support_ok(void); -int rtems_gdb_stub_get_current_thread(void); -int rtems_gdb_stub_get_next_thread(int); -int rtems_gdb_stub_get_offsets( - unsigned char **text_addr, - unsigned char **data_addr, - unsigned char **bss_addr -); -int rtems_gdb_stub_get_thread_regs( - int thread, - unsigned int *registers -); -int rtems_gdb_stub_set_thread_regs( - int thread, - unsigned int *registers -); -void rtems_gdb_process_query( - char *inbuffer, - char *outbuffer, - int do_threads, - int thread -); - -/** @brief Exception IDs */ -#define LM32_EXCEPTION_RESET 0x0 -#define LM32_EXCEPTION_INST_BREAKPOINT 0x1 -#define LM32_EXCEPTION_INST_BUS_ERROR 0x2 -#define LM32_EXCEPTION_DATA_BREAKPOINT 0x3 -#define LM32_EXCEPTION_DATA_BUS_ERROR 0x4 -#define LM32_EXCEPTION_DIVIDE_BY_ZERO 0x5 -#define LM32_EXCEPTION_INTERRUPT 0x6 -#define LM32_EXCEPTION_SYSTEM_CALL 0x7 - -/** @brief Breakpoint instruction */ -#define LM32_BREAK 0xac000002UL - -/** @brief This numbering must be consistant with GDBs numbering in gdb/lm32-tdep.c */ -enum lm32_regnames { - LM32_REG_R0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4, LM32_REG_R5, - LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9, LM32_REG_R10, - LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14, LM32_REG_R15, - LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19, LM32_REG_R20, - LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24, LM32_REG_R25, - LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA, LM32_REG_EA, LM32_REG_BA, - LM32_REG_PC, LM32_REG_EID, LM32_REG_EBA, LM32_REG_DEBA, LM32_REG_IE, NUM_REGS -}; - -/* keep this in sync with the debug isr handler in lm32-debug.S */ -enum lm32_int_regnames { - LM32_INT_REG_R1, LM32_INT_REG_R2, LM32_INT_REG_R3, LM32_INT_REG_R4, - LM32_INT_REG_R5, LM32_INT_REG_R6, LM32_INT_REG_R7, LM32_INT_REG_R8, - LM32_INT_REG_R9, LM32_INT_REG_R10, LM32_INT_REG_RA, LM32_INT_REG_EA, - LM32_INT_REG_BA, LM32_INT_REG_R11, LM32_INT_REG_R12, LM32_INT_REG_R13, - LM32_INT_REG_R14, LM32_INT_REG_R15, LM32_INT_REG_R16, LM32_INT_REG_R17, - LM32_INT_REG_R18, LM32_INT_REG_R19, LM32_INT_REG_R20, LM32_INT_REG_R21, - LM32_INT_REG_R22, LM32_INT_REG_R23, LM32_INT_REG_R24, LM32_INT_REG_R25, - LM32_INT_REG_GP, LM32_INT_REG_FP, LM32_INT_REG_SP, LM32_INT_REG_PC, - LM32_INT_REG_EID, LM32_INT_REG_EBA, LM32_INT_REG_DEBA, LM32_INT_REG_IE, -}; - -#endif /* _GDB_IF_H */ - -/** @} */ diff --git a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-debug.S b/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-debug.S deleted file mode 100644 index 7bd2c504e2..0000000000 --- a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-debug.S +++ /dev/null @@ -1,338 +0,0 @@ -/* - * lm32 debug exception vectors - * - * Michael Walle , 2009 - * - * If debugging is enabled the debug exception base address (deba) gets - * remapped to this file. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - * - */ - -#include "bspopts.h" - -.section .text -/* (D)EBA alignment */ -.align 256 -.globl _deba - -_deba: -debug_reset_handler: - /* Clear r0 */ - xor r0,r0,r0 - /* Disable interrupts */ - wcsr IE, r0 - /* Mask all interrupts */ - wcsr IM,r0 - /* Jump to original crt0 */ - .extern crt0 - mvhi r1, hi(crt0) - ori r1, r1, lo(crt0) - b r1 - nop - nop -debug_breakpoint_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ba - calli save_all - calli handle_exception - calli b_restore_and_return -debug_instruction_bus_error_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ea - calli save_all - calli handle_exception - calli e_restore_and_return -debug_watchpoint_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ba - calli save_all - calli handle_exception - calli b_restore_and_return -debug_data_bus_error_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ea - calli save_all - calli handle_exception - calli e_restore_and_return -debug_divide_by_zero_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ea - calli save_all - calli handle_exception - calli e_restore_and_return -debug_interrupt_handler: - bi debug_isr_handler - nop - nop - nop - nop - nop - nop - nop -debug_system_call_handler: - /* Clear r0 in case it was corrupted */ - xor r0, r0, r0 - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - sw (r0+116), ra - sw (r0+128), ea - calli save_all - calli handle_exception - calli e_restore_and_return - -debug_isr_handler: - addi sp, sp, -156 - sw (sp+4), r1 - sw (sp+8), r2 - sw (sp+12), r3 - sw (sp+16), r4 - sw (sp+20), r5 - sw (sp+24), r6 - sw (sp+28), r7 - sw (sp+32), r8 - sw (sp+36), r9 - sw (sp+40), r10 - sw (sp+44), ra - sw (sp+48), ea - sw (sp+52), ba - sw (sp+56), r11 - sw (sp+60), r12 - sw (sp+64), r13 - sw (sp+68), r14 - sw (sp+72), r15 - sw (sp+76), r16 - sw (sp+80), r17 - sw (sp+84), r18 - sw (sp+88), r19 - sw (sp+92), r20 - sw (sp+96), r21 - sw (sp+100), r22 - sw (sp+104), r23 - sw (sp+108), r24 - sw (sp+112), r25 - sw (sp+116), r26 - sw (sp+120), r27 - /* 124 - SP */ - addi r1, sp, 156 - sw (sp+124), r1 - /* 128 - PC */ - sw (sp+128), ea - /* 132 - EID */ - mvi r1, 6 - sw (sp+132), r1 - rcsr r1, EBA - sw (sp+136), r1 - rcsr r1, DEBA - sw (sp+140), r1 - rcsr r1, IE - sw (sp+144), r1 - - /* This is the same code as in cpu_asm.S */ - rcsr r2, IP - rcsr r3, IM - mv r1, r0 - and r2, r2, r3 - mvi r3, 1 - be r2, r0, 3f -1: - and r4, r2, r3 - bne r4, r0, 2f - sli r3, r3, 1 - addi r1, r1, 1 - bi 1b -2: - addi r2, sp, 4 - - .extern __ISR_Handler - mvhi r3, hi(__ISR_Handler) - ori r3, r3, lo(__ISR_Handler) - call r3 -3: - lw r1, (sp+4) - lw r2, (sp+8) - lw r3, (sp+12) - lw r4, (sp+16) - lw r5, (sp+20) - lw r6, (sp+24) - lw r7, (sp+28) - lw r8, (sp+32) - lw r9, (sp+36) - lw r10, (sp+40) - lw ra, (sp+44) - lw ea, (sp+48) - lw ba, (sp+52) - lw r11, (sp+56) - lw r12, (sp+60) - lw r13, (sp+64) - lw r14, (sp+68) - lw r15, (sp+72) - lw r16, (sp+76) - lw r17, (sp+80) - lw r18, (sp+84) - lw r19, (sp+88) - lw r20, (sp+92) - lw r21, (sp+96) - lw r22, (sp+100) - lw r23, (sp+104) - lw r24, (sp+108) - lw r25, (sp+112) - lw r26, (sp+116) - lw r27, (sp+120) - lw ea, (sp+136) - wcsr EBA, ea - lw ea, (sp+140) - wcsr DEBA, ea - /* Restore EA from PC */ - lw ea, (sp+128) - /* Stack pointer must be restored last, in case it has been updated */ - lw sp, (sp+124) - eret - -save_all: - sw (r0+4), r1 - sw (r0+8), r2 - sw (r0+12), r3 - sw (r0+16), r4 - sw (r0+20), r5 - sw (r0+24), r6 - sw (r0+28), r7 - sw (r0+32), r8 - sw (r0+36), r9 - sw (r0+40), r10 - sw (r0+44), r11 - sw (r0+48), r12 - sw (r0+52), r13 - sw (r0+56), r14 - sw (r0+60), r15 - sw (r0+64), r16 - sw (r0+68), r17 - sw (r0+72), r18 - sw (r0+76), r19 - sw (r0+80), r20 - sw (r0+84), r21 - sw (r0+88), r22 - sw (r0+92), r23 - sw (r0+96), r24 - sw (r0+100), r25 - sw (r0+104), r26 - sw (r0+108), r27 - sw (r0+112), sp - /* 116 - RA - saved in handler code above */ - sw (r0+120), ea - sw (r0+124), ba - /* 128 - PC - saved in handler code above */ - /* 132 - EID - saved below */ - rcsr r1, EBA - sw (r0+136), r1 - rcsr r1, DEBA - sw (r0+140), r1 - rcsr r1, IE - sw (r0+144), r1 - - /* Work out EID from exception entry point address */ - andi r1, ra, 0xff - srui r1, r1, 5 - sw (r0+132), r1 - - /* Save pointer to registers */ - mv r1, r0 - - /* Restore r0 to 0 */ - xor r0, r0, r0 - - /* Save r0 (hardcoded to 0) */ - sw (r1+0), r0 - ret - - -/* Restore gp registers */ -restore_gp: - lw r1, (r0+4) - lw r2, (r0+8) - lw r3, (r0+12) - lw r4, (r0+16) - lw r5, (r0+20) - lw r6, (r0+24) - lw r7, (r0+28) - lw r8, (r0+32) - lw r9, (r0+36) - lw r10, (r0+40) - lw r11, (r0+44) - lw r12, (r0+48) - lw r13, (r0+52) - lw r14, (r0+56) - lw r15, (r0+60) - lw r16, (r0+64) - lw r17, (r0+68) - lw r18, (r0+72) - lw r19, (r0+76) - lw r20, (r0+80) - lw r21, (r0+84) - lw r22, (r0+88) - lw r23, (r0+92) - lw r24, (r0+96) - lw r25, (r0+100) - lw r26, (r0+104) - lw r27, (r0+108) - ret - -/* Restore registers and return from exception */ -e_restore_and_return: - /* first restore gp registers */ - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - calli restore_gp - lw sp, (r0+112) - lw ra, (r0+116) - lw ba, (r0+124) - lw ea, (r0+136) - wcsr EBA, ea - lw ea, (r0+140) - wcsr DEBA, ea - /* Restore EA from PC */ - lw ea, (r0+128) - xor r0, r0, r0 - eret - -/* Restore registers and return from breakpoint */ -b_restore_and_return: - /* first restore gp registers */ - mvhi r0, hi(registers) - ori r0, r0, lo(registers) - calli restore_gp - lw sp, (r0+112) - lw ra, (r0+116) - lw ea, (r0+120) - lw ba, (r0+136) - wcsr EBA, ba - lw ba, (r0+140) - wcsr DEBA, ba - /* Restore BA from PC */ - lw ba, (r0+128) - xor r0, r0, r0 - bret - diff --git a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c b/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c deleted file mode 100644 index 8ca1a91054..0000000000 --- a/c/src/lib/libbsp/lm32/shared/gdbstub/lm32-stub.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Low-level support for LM32 remote debuging with GDB. - * Contributed by Jon Beniston - * Modified for RTEMS with thread support by Michael Walle - * - * 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. - */ - - -#include -#include -#include -#include -#include -#include "gdb_if.h" - -/* Enable support for run-length encoding */ -#undef GDB_RLE_ENABLED -/* Enable support for restart packets */ -#undef GDB_RESTART_ENABLED - -#define GDB_STUB_ENABLE_THREAD_SUPPORT - -/* - * The following external functions provide character input and output. - */ -extern char gdb_get_debug_char(void); -extern void gdb_put_debug_char(char); -extern void gdb_console_init(void); -extern void gdb_ack_irq(void); -extern void *_deba; - -/* Function prototypes */ -static void allow_nested_exception(void); -static void disallow_nested_exception(void); -static char *mem2hex(unsigned char *mem, char *buf, int count); -static unsigned char *hex2mem(char *buf, unsigned char *mem, int count); -static unsigned char *bin2mem(char *buf, unsigned char *mem, int count); -static int compute_signal(int eid); -static void flush_cache(void); -static int hex2int(char **ptr, int *int_value); -static char *getpacket(void); -static void putpacket(char *buffer); - -unsigned int registers[NUM_REGS]; - -/* BUFMAX defines the maximum number of characters in inbound/outbound buffers */ -#define BUFMAX 1500 - -/* I/O packet buffers */ -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; - -/* - * Set by debugger to indicate that when handling memory faults (bus errors), the - * handler should set the mem_err flag and skip over the faulting instruction - */ -static volatile int may_fault; - -/* - * Set by bus error exception handler, this indicates to caller of mem2hex, - * hex2mem or bin2mem that there has been an error. - */ -static volatile int mem_err; - -/* Indicates if we're single stepping */ -static unsigned char stepping; -static char branch_step; - -/* Saved instructions */ -static unsigned int *seq_ptr; -static unsigned int seq_insn; -static unsigned int *branch_ptr; -static unsigned int branch_insn; - -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) -static char do_threads; -int current_thread_registers[NUM_REGS]; -#endif - -/* this mapping is used to copy the registers from a debug interrupt frame - * see gdb_handle_break() */ -static unsigned char reg_map[] = { - 0, LM32_INT_REG_R1, LM32_INT_REG_R2, LM32_INT_REG_R3, LM32_INT_REG_R4, - LM32_INT_REG_R5, LM32_INT_REG_R6, LM32_INT_REG_R7, LM32_INT_REG_R8, - LM32_INT_REG_R9, LM32_INT_REG_R10, LM32_INT_REG_R11, LM32_INT_REG_R12, - LM32_INT_REG_R13, LM32_INT_REG_R14, LM32_INT_REG_R15, LM32_INT_REG_R16, - LM32_INT_REG_R17, LM32_INT_REG_R18, LM32_INT_REG_R19, LM32_INT_REG_R20, - LM32_INT_REG_R21, LM32_INT_REG_R22, LM32_INT_REG_R23, LM32_INT_REG_R24, - LM32_INT_REG_R25, LM32_INT_REG_GP, LM32_INT_REG_FP, LM32_INT_REG_SP, - LM32_INT_REG_RA, LM32_INT_REG_EA, LM32_INT_REG_BA, LM32_INT_REG_PC, - LM32_INT_REG_EID, LM32_INT_REG_EBA, LM32_INT_REG_DEBA, LM32_INT_REG_IE -}; - -/* - * Conversion helper functions - */ - -/* For integer to ASCII conversion */ -#define highhex(x) gdb_hexchars [(x >> 4) & 0xf] -#define lowhex(x) gdb_hexchars [x & 0xf] -const char gdb_hexchars[]="0123456789abcdef"; - -/* Convert ch from a hex digit to an int */ -static int hex( - unsigned char ch -) -{ - if (ch >= 'a' && ch <= 'f') - return ch-'a'+10; - if (ch >= '0' && ch <= '9') - return ch-'0'; - if (ch >= 'A' && ch <= 'F') - return ch-'A'+10; - return -1; -} - -/* - * Convert the memory pointed to by mem into hex, placing result in buf. - * Return a pointer to the last char put in buf ('\0'), in case of mem fault, - * return NULL. - */ -static char *mem2hex( - unsigned char *mem, - char *buf, int count -) -{ - unsigned char ch; - - while (count-- > 0) - { - ch = *mem++; - if (mem_err) - return NULL; - *buf++ = highhex(ch); - *buf++ = lowhex(ch); - } - - *buf = '\0'; - return buf; -} - -/* - * Convert the hex array pointed to by buf into binary to be placed in mem. - * Return a pointer to the character AFTER the last byte written. - */ -static unsigned char *hex2mem( - char *buf, - unsigned char *mem, - int count -) -{ - int i; - unsigned char ch; - - for (i = 0; i < count; i++) - { - /* Convert hex data to 8-bit value */ - ch = hex(*buf++) << 4; - ch |= hex(*buf++); - /* Attempt to write data to memory */ - *mem++ = ch; - /* Return NULL if write caused an exception */ - if (mem_err) - return NULL; - } - return mem; -} - -/* - * Copy the binary data pointed to by buf to mem and return a pointer to the - * character AFTER the last byte written $, # and 0x7d are escaped with 0x7d. - */ -static unsigned char *bin2mem( - char *buf, - unsigned char *mem, - int count -) -{ - int i; - unsigned char c; - - for (i = 0; i < count; i++) - { - /* Convert binary data to unsigned byte */ - c = *buf++; - if (c == 0x7d) - c = *buf++ ^ 0x20; - /* Attempt to write value to memory */ - *mem++ = c; - /* Return NULL if write caused an exception */ - if (mem_err) - return NULL; - } - - return mem; -} - -/* - * While we find nice hex chars, build an int. - * Return number of chars processed. - */ -static int hex2int( - char **ptr, - int *int_value -) -{ - int num_chars = 0; - int hex_value; - - *int_value = 0; - - while(**ptr) - { - hex_value = hex(**ptr); - if (hex_value < 0) - break; - - *int_value = (*int_value << 4) | hex_value; - num_chars ++; - - (*ptr)++; - } - - return (num_chars); -} - -/* Convert the exception identifier to a signal number. */ -static int compute_signal( - int eid -) -{ - switch (eid) - { - case LM32_EXCEPTION_RESET: - return 0; - case LM32_EXCEPTION_INTERRUPT: - return SIGINT; - case LM32_EXCEPTION_DATA_BREAKPOINT: - case LM32_EXCEPTION_INST_BREAKPOINT: - return SIGTRAP; - case LM32_EXCEPTION_INST_BUS_ERROR: - case LM32_EXCEPTION_DATA_BUS_ERROR: - return SIGSEGV; - case LM32_EXCEPTION_DIVIDE_BY_ZERO: - return SIGFPE; - } - - return SIGHUP; /* default for things we don't know about */ -} - -/* Scan for the sequence $# */ -static char *getpacket(void) -{ - char *buffer = &remcomInBuffer[0]; - unsigned char checksum; - unsigned char xmitcsum; - int count; - char ch; - - while (1) - { - /* wait around for the start character, ignore all other characters */ - while ((ch = gdb_get_debug_char()) != '$'); - -retry: - checksum = 0; - xmitcsum = -1; - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) - { - ch = gdb_get_debug_char(); - if (ch == '$') - goto retry; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - buffer[count] = 0; - - if (ch == '#') - { - ch = gdb_get_debug_char(); - xmitcsum = hex(ch) << 4; - ch = gdb_get_debug_char(); - xmitcsum += hex(ch); - - if (checksum != xmitcsum) - { - /* failed checksum */ - gdb_put_debug_char('-'); - } - else - { - /* successful transfer */ - gdb_put_debug_char('+'); - - /* if a sequence char is present, reply the sequence ID */ - if (buffer[2] == ':') - { - gdb_put_debug_char(buffer[0]); - gdb_put_debug_char(buffer[1]); - - return &buffer[3]; - } - - return &buffer[0]; - } - } - } -} - -/* Send the packet in buffer. */ -static void putpacket( - char *buffer -) -{ - unsigned char checksum; - int count; - unsigned char ch; - -#ifdef GDB_RLE_ENABLED - int run_length; - int run_idx; - char run_length_char; -#endif - - /* $#. */ - do { - gdb_put_debug_char('$'); - checksum = 0; - count = 0; - -#ifdef GDB_RLE_ENABLED - while (ch = buffer[count]) - { - /* Transmit character */ - gdb_put_debug_char(ch); - checksum += ch; - count += 1; - - /* - * Determine how many consecutive characters there are that are the same - * as the character we just transmitted - */ - run_length = 0; - run_idx = count; - while ((buffer[run_idx++] == ch) && (run_length < 97)) - run_length++; - /* Encode run length as an ASCII character */ - run_length_char = (char)(run_length + 29); - if ( (run_length >= 3) - && (run_length_char != '$') - && (run_length_char != '#') - && (run_length_char != '+') - && (run_length_char != '-') - ) - { - /* Transmit run-length */ - gdb_put_debug_char('*'); - checksum += '*'; - gdb_put_debug_char(run_length_char); - checksum += run_length_char; - count += run_length; - } - } -#else - while ((ch = buffer[count])) - { - gdb_put_debug_char(ch); - checksum += ch; - count += 1; - } -#endif - - gdb_put_debug_char('#'); - gdb_put_debug_char(highhex(checksum)); - gdb_put_debug_char(lowhex(checksum)); - } while (gdb_get_debug_char() != '+'); -} - -static void allow_nested_exception(void) -{ - mem_err = 0; - may_fault = 1; -} - -static void disallow_nested_exception(void) -{ - mem_err = 0; - may_fault = 0; -} - -/* Flush the instruction cache */ -static void flush_cache(void) -{ - /* - * Executing this does no harm on CPUs without a cache. We flush data cache as - * well as instruction cache in case the debugger has accessed memory - * directly. - */ - __asm__ __volatile__ ("wcsr ICC, r0\n" - "nop\n" - "nop\n" - "nop\n" - "wcsr DCC, r0\n" - "nop\n" - "nop\n" - "nop" - ); -} - -/* Set a h/w breakpoint at the given address */ -static int set_hw_breakpoint( - int address, - int length -) -{ - int bp; - - /* Find a free break point register and then set it */ - __asm__ ("rcsr %0, BP0" : "=r" (bp)); - if ((bp & 0x01) == 0) - { - __asm__ ("wcsr BP0, %0" : : "r" (address | 1)); - return 1; - } - __asm__ ("rcsr %0, BP1" : "=r" (bp)); - if ((bp & 0x01) == 0) - { - __asm__ ("wcsr BP1, %0" : : "r" (address | 1)); - return 1; - } - __asm__ ("rcsr %0, BP2" : "=r" (bp)); - if ((bp & 0x01) == 0) - { - __asm__ ("wcsr BP2, %0" : : "r" (address | 1)); - return 1; - } - __asm__ ("rcsr %0, BP3" : "=r" (bp)); - if ((bp & 0x01) == 0) - { - __asm__ ("wcsr BP3, %0" : : "r" (address | 1)); - return 1; - } - - /* No free breakpoint registers */ - return -1; -} - -/* Remove a h/w breakpoint which should be set at the given address */ -static int disable_hw_breakpoint( - int address, - int length -) -{ - int bp; - - /* Try to find matching breakpoint register */ - __asm__ ("rcsr %0, BP0" : "=r" (bp)); - if ((bp & 0xfffffffc) == (address & 0xfffffffc)) - { - __asm__ ("wcsr BP0, %0" : : "r" (0)); - return 1; - } - __asm__ ("rcsr %0, BP1" : "=r" (bp)); - if ((bp & 0xfffffffc) == (address & 0xfffffffc)) - { - __asm__ ("wcsr BP1, %0" : : "r" (0)); - return 1; - } - __asm__ ("rcsr %0, BP2" : "=r" (bp)); - if ((bp & 0xfffffffc) == (address & 0xfffffffc)) - { - __asm__ ("wcsr BP2, %0" : : "r" (0)); - return 1; - } - __asm__ ("rcsr %0, BP3" : "=r" (bp)); - if ((bp & 0xfffffffc) == (address & 0xfffffffc)) - { - __asm__ ("wcsr BP3, %0" : : "r" (0)); - return 1; - } - - /* Breakpoint not found */ - return -1; -} - -/* - * This support function prepares and sends the message containing the - * basic information about this exception. - */ -static void gdb_stub_report_exception_info( - int thread -) -{ - char *ptr; - int sigval; - - /* Convert exception ID to a signal number */ - sigval = compute_signal(registers[LM32_REG_EID]); - - /* Set pointer to start of output buffer */ - ptr = remcomOutBuffer; - - *ptr++ = 'T'; - *ptr++ = highhex(sigval); - *ptr++ = lowhex(sigval); - - *ptr++ = highhex(LM32_REG_PC); - *ptr++ = lowhex(LM32_REG_PC); - *ptr++ = ':'; - ptr = mem2hex((unsigned char *)&(registers[LM32_REG_PC]), ptr, 4); - *ptr++ = ';'; - - *ptr++ = highhex(LM32_REG_SP); - *ptr++ = lowhex(LM32_REG_SP); - *ptr++ = ':'; - ptr = mem2hex((unsigned char *)&(registers[LM32_REG_SP]), ptr, 4); - *ptr++ = ';'; - -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if (do_threads) - { - *ptr++ = 't'; - *ptr++ = 'h'; - *ptr++ = 'r'; - *ptr++ = 'e'; - *ptr++ = 'a'; - *ptr++ = 'd'; - *ptr++ = ':'; - ptr = thread2vhstr(ptr, thread); - *ptr++ = ';'; - } -#endif - - *ptr++ = '\0'; -} - -/* - * This function does all command procesing for interfacing to gdb. The error - * codes we return are errno numbers. - */ -void handle_exception(void) -{ - int addr; - int length; - char *ptr; - int err; - int reg; - unsigned insn; - unsigned opcode; - unsigned branch_target = 0; - int current_thread; - int thread; - void *regptr; - int host_has_detached = 0; - int binary; - - thread = 0; -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if (do_threads) - thread = rtems_gdb_stub_get_current_thread(); -#endif - current_thread = thread; - - /* - * Check for bus error caused by this code (rather than the program being - * debugged) - */ - if (may_fault && (registers[LM32_REG_EID] == LM32_EXCEPTION_DATA_BUS_ERROR)) - { - /* Indicate that a fault occured */ - mem_err = 1; - /* Skip over faulting instruction */ - registers[LM32_REG_PC] += 4; - /* Resume execution */ - return; - } - - if (stepping) - { - /* Remove breakpoints */ - *seq_ptr = seq_insn; - if (branch_step) - *branch_ptr = branch_insn; - stepping = 0; - } - - /* Reply to host that an exception has occured with some basic info */ - gdb_stub_report_exception_info(thread); - putpacket(remcomOutBuffer); - - while (!host_has_detached) - { - remcomOutBuffer[0] = '\0'; - ptr = getpacket(); - binary = 0; - - switch (*ptr++) - { - /* Return last signal */ - case '?': - gdb_stub_report_exception_info(thread); - break; - - /* Detach - exit from debugger */ - case 'D': - strcpy(remcomOutBuffer, "OK"); - host_has_detached = 1; - break; - - /* Return the value of the CPU registers */ - case 'g': - regptr = registers; -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if (do_threads && current_thread != thread ) - regptr = ¤t_thread_registers; -#endif - ptr = mem2hex((unsigned char*)regptr, remcomOutBuffer, NUM_REGS * 4); - break; - - /* Set the value of the CPU registers */ - case 'G': - regptr = registers; -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if (do_threads && current_thread != thread ) - regptr = ¤t_thread_registers; -#endif - hex2mem(ptr, (unsigned char*)regptr, NUM_REGS * 4); - strcpy(remcomOutBuffer, "OK"); - break; - - /* Return the value of the specified register */ - case 'p': - if (hex2int(&ptr, ®)) - { - ptr = remcomOutBuffer; - ptr = mem2hex((unsigned char *)®isters[reg], ptr, 4); - } else - strcpy(remcomOutBuffer, "E22"); - break; - - /* Set the specified register to the given value */ - case 'P': - if (hex2int(&ptr, ®) - && *ptr++ == '=') - { - hex2mem(ptr, (unsigned char *)®isters[reg], 4); - strcpy(remcomOutBuffer, "OK"); - } - else - strcpy(remcomOutBuffer, "E22"); - break; - - /* Read memory */ - case 'm': - /* Try to read %x,%x. */ - if (hex2int(&ptr, &addr) - && *ptr++ == ',' - && hex2int(&ptr, &length) - && length < (sizeof(remcomOutBuffer)/2)) - { - allow_nested_exception(); - if (NULL == mem2hex((unsigned char *)addr, remcomOutBuffer, length)) - strcpy(remcomOutBuffer, "E14"); - disallow_nested_exception(); - } - else - strcpy(remcomOutBuffer,"E22"); - break; - - /* Write memory */ - case 'X': - binary = 1; - case 'M': - /* Try to read '%x,%x:'. */ - if (hex2int(&ptr, &addr) - && *ptr++ == ',' - && hex2int(&ptr, &length) - && *ptr++ == ':') - { - allow_nested_exception(); - if (binary) - err = (int)bin2mem(ptr, (unsigned char *)addr, length); - else - err = (int)hex2mem(ptr, (unsigned char *)addr, length); - if (err) - strcpy(remcomOutBuffer, "OK"); - else - strcpy(remcomOutBuffer, "E14"); - disallow_nested_exception(); - } - else - strcpy(remcomOutBuffer, "E22"); - break; - - /* Continue */ - case 'c': - /* try to read optional parameter, pc unchanged if no parm */ - if (hex2int(&ptr, &addr)) - registers[LM32_REG_PC] = addr; - flush_cache(); - return; - - /* Step */ - case 's': - /* try to read optional parameter, pc unchanged if no parm */ - if (hex2int(&ptr, &addr)) - registers[LM32_REG_PC] = addr; - stepping = 1; - /* Is instruction a branch? */ - insn = *(unsigned int*)registers[LM32_REG_PC]; - opcode = insn & 0xfc000000; - if ( (opcode == 0xe0000000) - || (opcode == 0xf8000000) - ) - { - branch_step = 1; - branch_target = registers[LM32_REG_PC] - + (((signed)insn << 6) >> 4); - } - else if ( (opcode == 0x44000000) - || (opcode == 0x48000000) - || (opcode == 0x4c000000) - || (opcode == 0x50000000) - || (opcode == 0x54000000) - || (opcode == 0x5c000000) - ) - { - branch_step = 1; - branch_target = registers[LM32_REG_PC] + - + (((signed)insn << 16) >> 14); - } - else if ( (opcode == 0xd8000000) - || (opcode == 0xc0000000) - ) - { - branch_step = 1; - branch_target = registers[(insn >> 21) & 0x1f]; - } - else - branch_step = 0; - - /* Set breakpoint after instruction we're stepping */ - seq_ptr = (unsigned int *)registers[LM32_REG_PC]; - seq_ptr++; - seq_insn = *seq_ptr; - *seq_ptr = LM32_BREAK; - - /* Make sure one insn doesn't get replaced twice */ - if (seq_ptr == (unsigned int*)branch_target) - branch_step = 0; - - if (branch_step) - { - /* Set breakpoint on branch target */ - branch_ptr = (unsigned int*)branch_target; - branch_insn = *branch_ptr; - *branch_ptr = LM32_BREAK; - } - flush_cache(); - return; - - case 'Z': - switch (*ptr++) - { - /* Insert h/w breakpoint */ - case '1': - if (*ptr++ == ',' - && hex2int(&ptr, &addr) - && *ptr++ == ',' - && hex2int(&ptr, &length)) - { - err = set_hw_breakpoint(addr, length); - if (err > 0) - strcpy(remcomOutBuffer, "OK"); - else if (err < 0) - strcpy(remcomOutBuffer, "E28"); - } - else - strcpy(remcomOutBuffer, "E22"); - break; - } - break; - - case 'z': - switch (*ptr++) - { - /* Remove h/w breakpoint */ - case '1': - if (*ptr++ == ',' - && hex2int(&ptr, &addr) - && *ptr++ == ',' - && hex2int(&ptr, &length)) - { - err = disable_hw_breakpoint(addr, length); - if (err > 0) - strcpy(remcomOutBuffer, "OK"); - else if (err < 0) - strcpy(remcomOutBuffer, "E28"); - } - else - strcpy(remcomOutBuffer, "E22"); - break; - } - break; - - /* Query */ - case 'q': -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - rtems_gdb_process_query( - remcomInBuffer, - remcomOutBuffer, - do_threads, - thread ); -#endif - break; - -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - /* Thread alive */ - case 'T': - { - int testThread; - - if (vhstr2thread(&remcomInBuffer[1], &testThread) == NULL) - { - strcpy(remcomOutBuffer, "E01"); - break; - } - - if (rtems_gdb_index_to_stub_id(testThread) == NULL) - strcpy(remcomOutBuffer, "E02"); - else - strcpy(remcomOutBuffer, "OK"); - } - break; -#endif - - /* Set thread */ - case 'H': -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if (remcomInBuffer[1] != 'g') - break; - - if (!do_threads) - break; - - { - int tmp, ret; - - /* Set new generic thread */ - if (vhstr2thread(&remcomInBuffer[2], &tmp) == NULL) - { - strcpy(remcomOutBuffer, "E01"); - break; - } - - /* 0 means `thread' */ - if (tmp == 0) - tmp = thread; - - if (tmp == current_thread) - { - /* No changes */ - strcpy(remcomOutBuffer, "OK"); - break; - } - - /* Save current thread registers if necessary */ - if (current_thread != thread) - { - ret = rtems_gdb_stub_set_thread_regs( - current_thread, (unsigned int *) ¤t_thread_registers); - } - - /* Read new registers if necessary */ - if (tmp != thread) - { - ret = rtems_gdb_stub_get_thread_regs( - tmp, (unsigned int *) ¤t_thread_registers); - - if (!ret) - { - /* Thread does not exist */ - strcpy(remcomOutBuffer, "E02"); - break; - } - } - - current_thread = tmp; - strcpy(remcomOutBuffer, "OK"); - } -#endif - break; - -#ifdef GDB_RESTART_ENABLED - /* Reset */ - case 'r': - case 'R': - /* We reset by branching to the reset exception handler. */ - registers[LM32_REG_PC] = 0; - return; -#endif - } - - /* reply to the request */ - putpacket(remcomOutBuffer); - } -} - -void gdb_handle_break(rtems_vector_number vector, CPU_Interrupt_frame *frame) -{ - int i; - unsigned int *int_regs = (unsigned int*)frame; - - /* copy extended frame to registers */ - registers[LM32_REG_R0] = 0; - for (i = 1; i < NUM_REGS; i++) - { - registers[i] = int_regs[reg_map[i]]; - } - - /* now call the real handler */ - handle_exception(); - gdb_ack_irq(); - - /* copy registers back to extended frame */ - for (i = 1; i < NUM_REGS; i++) - { - int_regs[reg_map[i]] = registers[i]; - } -} - -void lm32_gdb_stub_install(int enable_threads) -{ - unsigned int dc; - - /* set DEBA and remap all exception */ - __asm__("wcsr DEBA, %0" : : "r" (&_deba)); - __asm__("rcsr %0, DC" : "=r" (dc)); - dc |= 0x2; - __asm__("wcsr DC, %0" : : "r" (dc)); - -#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT) - if( enable_threads ) - do_threads = 1; - else - do_threads = 0; -#endif - - gdb_console_init(); -} - -- cgit v1.2.3