bsps: Move GDB stubs to bsps

This patch is a part of the BSP source reorganization.

Update #3285.
This commit is contained in:
Sebastian Huber
2018-04-23 12:06:14 +02:00
parent 4ccbac6307
commit fd67814e06
11 changed files with 0 additions and 0 deletions

View File

@@ -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);
}

View File

@@ -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 */
/** @} */

View File

@@ -1,338 +0,0 @@
/*
* lm32 debug exception vectors
*
* Michael Walle <michael@walle.cc>, 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

View File

@@ -1,977 +0,0 @@
/*
* Low-level support for LM32 remote debuging with GDB.
* Contributed by Jon Beniston <jon@beniston.com>
* Modified for RTEMS with thread support by Michael Walle <michael@walle.cc>
*
* 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 <bsp.h>
#include <string.h>
#include <signal.h>
#include <rtems.h>
#include <rtems/score/cpu.h>
#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 $<data>#<checksum> */
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
/* $<packet info>#<checksum>. */
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 = &current_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 = &current_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, &reg))
{
ptr = remcomOutBuffer;
ptr = mem2hex((unsigned char *)&registers[reg], ptr, 4);
} else
strcpy(remcomOutBuffer, "E22");
break;
/* Set the specified register to the given value */
case 'P':
if (hex2int(&ptr, &reg)
&& *ptr++ == '=')
{
hex2mem(ptr, (unsigned char *)&registers[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 *) &current_thread_registers);
}
/* Read new registers if necessary */
if (tmp != thread)
{
ret = rtems_gdb_stub_get_thread_regs(
tmp, (unsigned int *) &current_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();
}

View File

@@ -1,195 +0,0 @@
/**
* @file
*
* @ingroup m68k_gdbstub
*
* @brief 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.
*/
#ifndef _GDB_IF_H
#define _GDB_IF_H
/**
* @defgroup m68k_gdbstub GDB Stub
*
* @ingroup m68k_shared
*
* @brief GDB Stub interface support
*/
/* 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
);
#if defined (__mc68000__)
/* there are 180 bytes of registers on a 68020 w/68881 */
/* many of the fpa registers are 12 byte (96 bit) registers */
#define NUMREGBYTES 180
enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
A0,A1,A2,A3,A4,A5,A6,A7,
PS,PC,
FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
FPCONTROL,FPSTATUS,FPIADDR
};
#elif defined (__mips__)
/*
* MIPS registers, numbered in the order in which gdb expects to see them.
*/
#define ZERO 0
#define AT 1
#define V0 2
#define V1 3
#define A0 4
#define A1 5
#define A2 6
#define A3 7
#define T0 8
#define T1 9
#define T2 10
#define T3 11
#define T4 12
#define T5 13
#define T6 14
#define T7 15
#define S0 16
#define S1 17
#define S2 18
#define S3 19
#define S4 20
#define S5 21
#define S6 22
#define S7 23
#define T8 24
#define T9 25
#define K0 26
#define K1 27
#define GP 28
#define SP 29
#define S8 30
#define RA 31
#define SR 32
#define LO 33
#define HI 34
#define BAD_VA 35
#define CAUSE 36
#define PC 37
#define F0 38
#define F1 39
#define F2 40
#define F3 41
#define F4 42
#define F5 43
#define F6 44
#define F7 45
#define F8 46
#define F9 47
#define F10 48
#define F11 49
#define F12 50
#define F13 51
#define F14 52
#define F15 53
#define F16 54
#define F17 55
#define F18 56
#define F19 57
#define F20 58
#define F21 59
#define F22 60
#define F23 61
#define F24 62
#define F25 63
#define F26 64
#define F27 65
#define F28 66
#define F29 67
#define F30 68
#define F31 69
#define FCSR 70
#define FIRR 71
#define NUM_REGS 72
void mips_gdb_stub_install(int enableThreads) ;
#endif /* defined (__mips__) */
#define MEMOPT_READABLE 1
#define MEMOPT_WRITEABLE 2
#define NUM_MEMSEGS 10
int gdbstub_add_memsegment(unsigned,unsigned,int);
#endif /* _GDB_IF_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,151 +0,0 @@
/*****************************************************/
Debugged this stub against the MongooseV bsp. Relies on putting break
instructions on breakpoints and step targets- normal stuff, and does not
employ hardware breakpoint support at this time. As written, a single
breakpoint in a loop will not be reasserted unless the user steps or has
a 2nd one, since breakpoints are only reset when the gdb stub is
re-entered. A useful enhancement would be to fix the break instruction
management so the stub could invisibly put a 2nd break after the 1st
"official" one so it can silently reset breakpoints. Shouldn't be too
hard, mostly a matter of working it out.
This was tested only against an R3000 MIPS. It should work OK on a
R4000. Needs to be tested at some point.
This stub supports threads as implemented by gdb 5 and doesn't have any
bugs I'm aware of.
Greg Menke
3/5/2002
/*****************************************************/
The contents of this directory are based upon the "r46kstub.tar.gz" package
released to the net by
C. M. Heard
VVNET, Inc. phone: +1 408 247 9376
4040 Moorpark Ave. Suite 206 fax: +1 408 244 3651
San Jose, CA 95117 USA e-mail: heard@vvnet.com
This package was released in the September 1996 time frame for use
with gdb 4.16 and an IDT R4600 Orion. The stub was modified to support
R3000 class CPUs and to work within the mips-rtems exeception processing
framework.
THe file memlimits.h could end up being target board dependent. If
this is the case, copy it to your BSP directory and modify as necessary.
--joel
8 February 2002
Original README
===============
The r46kstub directory and its compressed archive (r46kstub.tar.gz) contain
the 9/29/96 source code snapshot for a ROM-resident gdb-4.16 debug agent
(aka stub) for the IDT R4600 Orion processor. It is based on the stub for
the Hitachi SH processor written by Ben Lee and Steve Chamberlain and
supplied with the gdb-4.16 distribution; that stub in turn was "originally
based on an m68k software stub written by Glenn Engel at HP, but has changed
quite a bit". The modifications for the R4600 were contributed by C. M.
Heard of VVNET, Inc. and were based in part on the Algorithmics R4000 version
of Phil Bunce's PMON program.
The distribution consists of the following files:
-rw-r--r-- 1 1178 Sep 29 16:34 ChangeLog
-rw-r--r-- 1 748 Jul 26 01:18 Makefile
-rw-r--r-- 1 6652 Sep 29 16:34 README
-rw-r--r-- 1 1829 May 21 02:02 gdb_if.h
-rw-r--r-- 1 3745 Sep 29 14:03 ioaddr.h
-rw-r--r-- 1 2906 Sep 29 14:39 limits.h
-rw-r--r-- 1 6552 May 23 00:17 mips_opcode.h
-rw-r--r-- 1 14017 May 21 02:04 r4600.h
-rw-r--r-- 1 23874 Jul 21 20:31 r46kstub.c
-rw-r--r-- 1 1064 Jul 3 12:35 r46kstub.ld
-rw-r--r-- 1 13299 Sep 29 16:24 stubinit.S
With the exception of mips_opcode.h, which is a slightly modified version
of a header file contributed by Ralph Campbell to 4.4 BSD and is therefore
copyrighted by the UC Regents, all of the source files have been dedicated
by their authors to the public domain. Use them as you wish, but do so
at your own risk! The authors accept _no_ responsibility for any errors.
The debug agent contained herein is at this writing in active use at VVNET
supporting initial hardware debug and board bring-up of an OC-12 ATM probe
board. It uses polled I/O on a 16C450 UART. We had originally intended to
add support for interrupts to allow gdb to break in on a running program,
but we have found that this is not really necessary since the reset button
will accomplish the same purpose (thanks to the MIPS feature of saving the
program counter in the ErrorEPC register when a reset exception occurs).
Be aware that this stub handles ALL interrupts and exceptions except for
reset (or NMI) in the same way -- by passing control to the debug command
loop. It of course uses the ROM exception vectors to do so. In order to
support code that actally needs to use interrupts we use use a more elaborate
stub that is linked with the downloaded program. It hooks the RAM exception
vectors and clears the BEV status bit to gain control. The ROM-based stub
is still used in this case for initial program loading.
In order to port this stub to a different platform you will at a minimum
need to customize the macros in limits.h (which define the limits of readable,
writeable, and steppable address space) and the I/O addresses in ioaddr.h
(which define the 16C450 MMIO addresses). If you use something other than
a 16C450 UART you will probably also need to modify the portions of stubinit.S
which deal with the serial port. I've tried to be careful to respect all the
architecturally-defined hazards as described in Appendix F of Kane and
Heinrich, MIPS RISC Architecture, in order to minimize the work in porting
to 4000-series processors other than the R4600, but no guarantees are offered.
Support is presently restricted to big-endian addressing, and I've not even
considered what changes would be needed for little-endian support.
When this stub is built with gcc-2.7.2 and binutils-2.6 you will see a few
warning messages from the single-step support routine where a cast is used
to sign-extend a pointer (the next instruction address) into a long long
(the PC image). Those warnings are expected; I've checked the generated
code and it is doing what I had intended. But you should not see any other
warnings or errors. Here is a log of the build:
mips64orion-idt-elf-gcc -g -Wa,-ahld -Wall -membedded-data \
-O3 -c r46kstub.c >r46kstub.L
r46kstub.c: In function `doSStep':
r46kstub.c:537: warning: cast to pointer from integer of different size
r46kstub.c:539: warning: cast to pointer from integer of different size
r46kstub.c:547: warning: cast to pointer from integer of different size
r46kstub.c:561: warning: cast to pointer from integer of different size
r46kstub.c:563: warning: cast to pointer from integer of different size
r46kstub.c:572: warning: cast to pointer from integer of different size
r46kstub.c:574: warning: cast to pointer from integer of different size
r46kstub.c:582: warning: cast to pointer from integer of different size
r46kstub.c:589: warning: cast to pointer from integer of different size
r46kstub.c:591: warning: cast to pointer from integer of different size
r46kstub.c:597: warning: cast to pointer from integer of different size
r46kstub.c:599: warning: cast to pointer from integer of different size
r46kstub.c:605: warning: cast to pointer from integer of different size
r46kstub.c:607: warning: cast to pointer from integer of different size
r46kstub.c:613: warning: cast to pointer from integer of different size
r46kstub.c:615: warning: cast to pointer from integer of different size
r46kstub.c:624: warning: cast to pointer from integer of different size
r46kstub.c:628: warning: cast to pointer from integer of different size
r46kstub.c:635: warning: cast to pointer from integer of different size
r46kstub.c:637: warning: cast to pointer from integer of different size
mips64orion-idt-elf-gcc -g -Wa,-ahld -Wall -membedded-data \
-O3 -c stubinit.S >stubinit.L
mips64orion-idt-elf-ld -t -s -T r46kstub.ld -Map r46kstub.map -o r46kstub.out
mips64orion-idt-elf-ld: mode elf32bmip
stubinit.o
r46kstub.o
mips64orion-idt-elf-objcopy -S -R .bss -R .data -R .reginfo \
-O srec r46kstub.out r46kstub.hex
Limitations: stubinit.S deliberately forces the PC (which is a 64-bit
register) to contain a legitimate sign-extended 32-bit value. This was
done to cope with a bug in gdb-4.16, which does _not_ properly sign-extend
the initial PC when it loads a program. This means that you cannot use
the "set" command to load an unmapped sixty-four bit virtual address into
the PC, as you can for all other registers.
Please send bug reports, comments, or suggestions for improvement to:

View File

@@ -1,194 +0,0 @@
/**
* @file
* @ingroup mips_gdb
* @brief Definition of the interface between 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 mips_gdb GDB Interface
* @ingroup mips_shared
* @brief GDB Interface
* @{
*/
#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];
};
/**
* @name 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
);
/** @} */
/**
* @name MIPS registers
* @brief Numbered in the order in which gdb expects to see them.
* @{
*/
#define ZERO 0
#define AT 1
#define V0 2
#define V1 3
#define A0 4
#define A1 5
#define A2 6
#define A3 7
#define T0 8
#define T1 9
#define T2 10
#define T3 11
#define T4 12
#define T5 13
#define T6 14
#define T7 15
#define S0 16
#define S1 17
#define S2 18
#define S3 19
#define S4 20
#define S5 21
#define S6 22
#define S7 23
#define T8 24
#define T9 25
#define K0 26
#define K1 27
#define GP 28
#define SP 29
#define S8 30
#define RA 31
#define SR 32
#define LO 33
#define HI 34
#define BAD_VA 35
#define CAUSE 36
#define PC 37
#define F0 38
#define F1 39
#define F2 40
#define F3 41
#define F4 42
#define F5 43
#define F6 44
#define F7 45
#define F8 46
#define F9 47
#define F10 48
#define F11 49
#define F12 50
#define F13 51
#define F14 52
#define F15 53
#define F16 54
#define F17 55
#define F18 56
#define F19 57
#define F20 58
#define F21 59
#define F22 60
#define F23 61
#define F24 62
#define F25 63
#define F26 64
#define F27 65
#define F28 66
#define F29 67
#define F30 68
#define F31 69
#define FCSR 70
#define FIRR 71
#define NUM_REGS 72
/** @} */
void mips_gdb_stub_install(int enableThreads) ;
#define MEMOPT_READABLE 1
#define MEMOPT_WRITEABLE 2
#ifndef NUM_MEMSEGS
#define NUM_MEMSEGS 10
#endif
int gdbstub_add_memsegment(unsigned,unsigned,int);
/** @} */
#endif /* _GDB_IF_H */

View File

@@ -1,100 +0,0 @@
/**
* @file
* @ingroup mips_limits
* @brief Definition of machine and system dependent address limits.
*/
/*
* limits.h - definition of machine & system dependent address limits
*
* 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.
*/
#ifndef _MEMLIMITS_H_
#define _MEMLIMITS_H_
/*
* The macros in this file are specific to a given implementation.
* The general rules for their construction are as follows:
*
* 1.) is_readable(addr,length) should be true if and only if the
* region starting at the given virtual address can be read
* _without_ causing an exception or other fatal error. Note
* that the stub will use the strictest alignment satisfied
* by _both_ addr and length (e.g., if both are divisible by
* 8 then the region will be read in double-word chunks).
*
* 2.) is_writeable(addr,length) should be true if and only if the
* region starting at the given virtual address can be written
* _without_ causing an exception or other fatal error. Note
* that the stub will use the strictest alignment satisfied
* by _both_ addr and length (e.g., if both are divisible by
* 8 then the region will be written in double-word chunks).
*
* 3.) is-steppable(ptr) whould be true if and only if ptr is the
* address of a writeable region of memory which may contain
* an executable instruction. At a minimum this requires that
* ptr be word-aligned (divisible by 4) and not point to EPROM
* or memory-mapped I/O.
*
* Note: in order to satisfy constraints related to cacheability
* of certain memory subsystems it may be necessary for regions
* of kseg0 and kseg1 which map to the same physical addresses
* to have different readability and/or writeability attributes.
*/
/**
* @defgroup mips_limits Address Limits
* @ingroup mips_shared
* @brief Address Limits
*/
/*
#define K0_LIMIT_FOR_READ (K0BASE+0x18000000)
#define K1_LIMIT_FOR_READ (K1BASE+K1SIZE)
#define is_readable(addr,length) \
(((K0BASE <= addr) && ((addr + length) <= K0_LIMIT_FOR_READ)) \
|| ((K1BASE <= addr) && ((addr + length) <= K1_LIMIT_FOR_READ)))
#define K0_LIMIT_FOR_WRITE (K0BASE+0x08000000)
#define K1_LIMIT_FOR_WRITE (K1BASE+0x1e000000)
#define is_writeable(addr,length) \
(((K0BASE <= addr) && ((addr + length) <= K0_LIMIT_FOR_WRITE)) \
|| ((K1BASE <= addr) && ((addr + length) <= K1_LIMIT_FOR_WRITE)))
#define K0_LIMIT_FOR_STEP (K0BASE+0x08000000)
#define K1_LIMIT_FOR_STEP (K1BASE+0x08000000)
#define is_steppable(ptr) \
((((int)ptr & 0x3) == 0) \
&& (((K0BASE <= (int)ptr) && ((int)ptr < K0_LIMIT_FOR_STEP)) \
|| ((K1BASE <= (int)ptr) && ((int)ptr < K1_LIMIT_FOR_STEP))))
struct memseg
{
unsigned begin, end, opts;
};
#define MEMOPT_READABLE 1
#define MEMOPT_WRITEABLE 2
#define NUM_MEMSEGS 10
int add_memsegment(unsigned,unsigned,int);
int is_readable(unsigned,unsigned);
int is_writeable(unsigned,unsigned);
int is_steppable(unsigned);
*/
#endif /* _MEMLIMITS_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,336 +0,0 @@
/**
* @file
* @ingroup
* @brief Instruction formats and opcode values for MIPS
*/
/*
* Copyright (c) 1992 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Ralph Campbell.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* from: @(#)mips_opcode.h 7.1 (Berkeley) 3/19/92
* via: mips_opcode.h,v 1.1 1994/03/10 16:15:10 (algorithmics)
*/
/*
* Define the instruction formats and opcode values for the
* MIPS instruction set.
*/
#ifndef _MIPS_OPCODE_H
#define _MIPS_OPCODE_H
/**
* @defgroup mips_ops MIPS Opcodes
* @ingroup mips_shared
* @brief MIPS Instruction Formats and Opcode Values
* @{
*/
/**
* @name Instruction formats
* @{
*/
typedef union {
unsigned word;
#ifdef MIPSEL
struct {
unsigned imm: 16;
unsigned rt: 5;
unsigned rs: 5;
unsigned op: 6;
} IType;
struct {
unsigned target: 26;
unsigned op: 6;
} JType;
struct {
unsigned func: 6;
unsigned shamt: 5;
unsigned rd: 5;
unsigned rt: 5;
unsigned rs: 5;
unsigned op: 6;
} RType;
struct {
unsigned func: 6;
unsigned fd: 5;
unsigned fs: 5;
unsigned ft: 5;
unsigned fmt: 4;
unsigned : 1; /* always '1' */
unsigned op: 6; /* always '0x11' */
} FRType;
#else
struct {
unsigned op: 6;
unsigned rs: 5;
unsigned rt: 5;
unsigned imm: 16;
} IType;
struct {
unsigned op: 6;
unsigned target: 26;
} JType;
struct {
unsigned op: 6;
unsigned rs: 5;
unsigned rt: 5;
unsigned rd: 5;
unsigned shamt: 5;
unsigned func: 6;
} RType;
struct {
unsigned op: 6; /* always '0x11' */
unsigned : 1; /* always '1' */
unsigned fmt: 4;
unsigned func: 6;
unsigned ft: 5;
unsigned fs: 5;
unsigned fd: 5;
} FRType;
#endif
} InstFmt;
/** @} */
/**
* @name 'op' field values
* @{
*/
#define OP_SPECIAL 000
#define OP_REGIMM 001
#define OP_J 002
#define OP_JAL 003
#define OP_BEQ 004
#define OP_BNE 005
#define OP_BLEZ 006
#define OP_BGTZ 007
#define OP_ADDI 010
#define OP_ADDIU 011
#define OP_SLTI 012
#define OP_SLTIU 013
#define OP_ANDI 014
#define OP_ORI 015
#define OP_XORI 016
#define OP_LUI 017
#define OP_COP0 020
#define OP_COP1 021
#define OP_COP2 022
#define OP_BEQL 024
#define OP_BNEL 025
#define OP_BLEZL 026
#define OP_BGTZL 027
#define OP_DADDI 030
#define OP_DADDIU 031
#define OP_LDL 032
#define OP_LDR 033
#define OP_LB 040
#define OP_LH 041
#define OP_LWL 042
#define OP_LW 043
#define OP_LBU 044
#define OP_LHU 045
#define OP_LWR 046
#define OP_LWU 047
#define OP_SB 050
#define OP_SH 051
#define OP_SWL 052
#define OP_SW 053
#define OP_SDL 054
#define OP_SDR 055
#define OP_SWR 056
#define OP_CACHE 057
#define OP_LL 060
#define OP_LWC1 061
#define OP_LWC2 062
#define OP_LLD 064
#define OP_LDC1 065
#define OP_LDC2 066
#define OP_LD 067
#define OP_SC 070
#define OP_SWC1 071
#define OP_SWC2 072
#define OP_SCD 074
#define OP_SDC1 075
#define OP_SDC2 076
#define OP_SD 077
/**
* @name 'func' field values when 'op' == OP_SPECIAL.
* @{
*/
#define OP_SLL 000
#define OP_SRL 002
#define OP_SRA 003
#define OP_SLLV 004
#define OP_SRLV 006
#define OP_SRAV 007
#define OP_JR 010
#define OP_JALR 011
#define OP_SYSCALL 014
#define OP_BREAK 015
#define OP_SYNC 017
#define OP_MFHI 020
#define OP_MTHI 021
#define OP_MFLO 022
#define OP_MTLO 023
#define OP_DSLLV 024
#define OP_DSRLV 026
#define OP_DSRAV 027
#define OP_MULT 030
#define OP_MULTU 031
#define OP_DIV 032
#define OP_DIVU 033
#define OP_DMULT 034
#define OP_DMULTU 035
#define OP_DDIV 036
#define OP_DDIVU 037
#define OP_ADD 040
#define OP_ADDU 041
#define OP_SUB 042
#define OP_SUBU 043
#define OP_AND 044
#define OP_OR 045
#define OP_XOR 046
#define OP_NOR 047
#define OP_SLT 052
#define OP_SLTU 053
#define OP_DADD 054
#define OP_DADDU 055
#define OP_DSUB 056
#define OP_DSUBU 057
#define OP_TGE 060
#define OP_TGEU 061
#define OP_TLT 062
#define OP_TLTU 063
#define OP_TEQ 064
#define OP_TNE 066
#define OP_DSLL 070
#define OP_DSRL 072
#define OP_DSRA 073
#define OP_DSLL32 074
#define OP_DSRL32 076
#define OP_DSRA32 077
/** @} */
/**
* 'func' field values when 'op' == OP_REGIMM.
* @{
*/
#define OP_BLTZ 000
#define OP_BGEZ 001
#define OP_BLTZL 002
#define OP_BGEZL 003
#define OP_TGEI 010
#define OP_TGEIU 011
#define OP_TLTI 012
#define OP_TLTIU 013
#define OP_TEQI 014
#define OP_TNEI 016
#define OP_BLTZAL 020
#define OP_BGEZAL 021
#define OP_BLTZALL 022
#define OP_BGEZALL 023
/** @} */
/**
* @name 'rs' field values when 'op' == OP_COPz.
* @{
*/
#define OP_MF 000
#define OP_DMF 001
#define OP_CF 002
#define OP_MT 004
#define OP_DMT 005
#define OP_CT 006
#define OP_BC 010
/** @} */
/**
* @name 'rt' field values when 'op' == OP_COPz and 'rt' == OP_BC.
* @{
*/
#define COPz_BCF 0x00
#define COPz_BCT 0x01
#define COPz_BCFL 0x02
#define COPz_BCTL 0x03
/** @} */
/**
* @name Instructions with specal significance to debuggers.
* @{
*/
#define BREAK_INSTR 0x0000000d ///< @brief instruction code for break
#define NOP_INSTR 0x00000000 ///< @brief instruction code for no-op
/** @} */
/** @} */
#endif /* _MIPS_OPCODE_H */