Index: bsps/lm32/shared/gdbstub/README
===================================================================
--- bsps/lm32/shared/gdbstub/README	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
+++ bsps/lm32/shared/gdbstub/README	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
@@ -0,0 +1,82 @@
+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);
+  }
+
Index: bsps/lm32/shared/gdbstub/gdb_if.h
===================================================================
--- bsps/lm32/shared/gdbstub/gdb_if.h	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
+++ bsps/lm32/shared/gdbstub/gdb_if.h	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
@@ -0,0 +1,125 @@
+/**
+ * @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 */
+
+/** @} */
Index: bsps/lm32/shared/gdbstub/lm32-debug.S
===================================================================
--- bsps/lm32/shared/gdbstub/lm32-debug.S	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
+++ bsps/lm32/shared/gdbstub/lm32-debug.S	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
@@ -0,0 +1,338 @@
+/*
+ *  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
+
Index: bsps/lm32/shared/gdbstub/lm32-stub.c
===================================================================
--- bsps/lm32/shared/gdbstub/lm32-stub.c	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
+++ bsps/lm32/shared/gdbstub/lm32-stub.c	(revision fd67814e06a734cd0d78274d61fc04c7af79b5fc)
@@ -0,0 +1,977 @@
+/*
+ * 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();
+}
+
