1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-29 16:03:14 +03:00

GDB support w/new toolchain and UART driver (#5559)

* Add full gdb support with uart/Serial integration

* Fix GDB merge errors

* Update to unpatched GDB protocol specification

It appears that Espressif patched the open source xtensa GDB port in
order to build their old GDB executable and their old gdbstub (basically
removing any register in a generic xtensa and only leaving those
present in the chip they synthesized).  Their GDBStub also assumed this
behavior.

Unpatched upstream GNU GDB now expects all the registers in
xtensa-config.c to be sent/read on a 'g' command.  Change the GDB stub
to send "xxxxxxxx"s (legal per the spec) for unimplemented registers.
This makes the 'g' response much longer, but it's results are cached
and in an interactive debugger it isn't noticeable.

* Fix .iram.literal to come before .iram.text for GDB

* Move functions to flash, call using wrappers

All functions which are not interrupt or exception called are now in
flash. A small IRAM wrapper enables flash when processing main GDB ops
by calling Cache_Read_Enable_New() and then jumping to the main flash
code.  This seems to work for catching exceptions, data and code breaks,
and Ctrl-C.

The UART ISR handler and exception handler register-saving bits of
code in ASM are still in IRAM.

GDB IRAM usage is now about 670 bytes.

* Remove LWIP2 builder commit

* Add documentation and gdbstub_init header

Add some simple GDB documentation to the main tree showing a worked
example.

Adds the definition of `void gdbstub_init()` to <GDBStub.h>

* Clean up GDB include and library dir

Replace GDBstub.h with the version in the internal/ directory, and
adjust stub code accordingly.  This way, only one copy of a file called
"GDBstub.h" will exist.

Update the gdbcommands and replace the obsolete ESPRESSIF readme with
@kylefleming's version since we're mainly doing serial, not TCP,
connected debugging.

Bump the library rev. number since this is a pretty big functionality
change.

Minor documentation tweak.

* Undo much of UART refactoring, set fifo IRQ to 16

Remove the refactoring of pin control and other little things not directly
related to GDB processing.  Should greatly reduce the diff size in uart.c.
Should also remove any register value changes (intended or otherwise)
introduced in the original PR from @kylefleming.

Set the FIFO interrupt to 16 chars when in GDB mode, matching the latest
UART configuration for highest speed.

* Add architecture comments, cleanup uart.c code

Comments added to UART.c trying to explain (as best as I understand it)
the changes done to support GDB and how they interact with standard
operation.

Fix the uart_uninit to stop the ISR and then free appropriately.

Fix uart_isr_handle_data (GDB's shim for sending chars to the 8266 app)
to do the exact same thing as the standard UART handler including set
the overflow properly and either discard or overwrite in that case.

Fix serial reception when GDB enabled by enabling the user recv ISR.

Remove commented attributes from gdbstub, leftover from the move to
flash.

General logic cleanup per comments in the PR.

* Also set the UART flags for HW error in GDB

Ensure we also check the UART flags and set the uart status
appropriately when in GDB mode.
This commit is contained in:
Earle F. Philhower, III
2019-01-23 20:51:35 +00:00
committed by Develo
parent 4657666319
commit bff3a6d963
16 changed files with 1411 additions and 691 deletions

View File

@ -1,6 +1,40 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
// this header is intentionally left blank
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#endif //GDBSTUB_H
#include "internal/gdbstub-cfg.h"
#ifdef __cplusplus
extern "C" {
#endif
void gdbstub_init();
//Indicates whether gdbstub will attach to these or not
//Useful for other uart libs to avoid conflicts
bool gdbstub_has_putc1_control();
bool gdbstub_has_uart_isr_control();
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
void gdbstub_set_putc1_callback(void (*callback)(char));
#endif
void gdbstub_write_char(char c);
void gdbstub_write(const char* buf, size_t size);
#if GDBSTUB_CTRLC_BREAK && !GDBSTUB_FREERTOS
void gdbstub_set_uart_isr_callback(void (*callback)(void*, uint8_t), void* arg);
//Override points for enabling tx and rx pins for uart0
void gdbstub_hook_enable_tx_pin_uart0(uint8_t pin);
void gdbstub_hook_enable_rx_pin_uart0(uint8_t pin);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,5 +1,5 @@
#ifndef GDBSTUB_CFG_H
#define GDBSTUB_CFG_H
#define GDBSTUB_CFG_H
/*
Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL
@ -19,6 +19,14 @@ stops when you run into an error in your code, try enabling this.
#define GDBSTUB_USE_OWN_STACK 0
#endif
/*
Enable this to cause the program to pause and wait for gdb to be connected when an exception is
encountered.
*/
#ifndef GDBSTUB_BREAK_ON_EXCEPTION
#define GDBSTUB_BREAK_ON_EXCEPTION 1
#endif
/*
If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by
hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't
@ -26,7 +34,7 @@ work for your program anymore. This will fail if your program sets an UART inter
the gdbstub_init call.
*/
#ifndef GDBSTUB_CTRLC_BREAK
#define GDBSTUB_CTRLC_BREAK 0
#define GDBSTUB_CTRLC_BREAK 1
#endif
/*
@ -35,7 +43,7 @@ will show up in your gdb session, which is useful if you use gdb to do stuff. It
you use a normal terminal, you can't read the printfs anymore.
*/
#ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT
#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 0
#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 1
#endif
/*
@ -55,7 +63,25 @@ flash somehow is disabled (eg during SPI operations or flash write/erase operati
are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most
likely crash.
*/
#define ATTR_GDBINIT ICACHE_FLASH_ATTR
#define ATTR_GDBFN ICACHE_RAM_ATTR
#ifndef ATTR_GDBINIT
#define ATTR_GDBINIT ICACHE_FLASH_ATTR
#endif
#ifndef ATTR_GDBFN
#define ATTR_GDBFN ICACHE_RAM_ATTR
#endif
#ifndef ATTR_GDBEXTERNFN
#define ATTR_GDBEXTERNFN ICACHE_FLASH_ATTR
#endif
#ifndef ASATTR_GDBINIT
#define ASATTR_GDBINIT .section .irom0.text
#endif
#ifndef ASATTR_GDBFN
#define ASATTR_GDBFN .section .iram.text
#endif
#ifndef ASATTR_GDBEXTERNFN
#define ASATTR_GDBEXTERNFN .section .irom0.text
#endif
#endif

View File

@ -24,10 +24,13 @@
.global gdbstub_exceptionStack
#endif
.text
ASATTR_GDBFN
.literal_position
.text
ASATTR_GDBINIT
.literal_position
ASATTR_GDBFN
.align 4
/*
@ -51,6 +54,7 @@ This is the debugging exception routine; it's called by the debugging vector
We arrive here with all regs intact except for a2. The old contents of A2 are saved
into the DEBUG_EXCSAVE special function register. EPC is the original PC.
*/
.type gdbstub_debug_exception_entry, @function
gdbstub_debug_exception_entry:
/*
//Minimum no-op debug exception handler, for debug
@ -64,32 +68,32 @@ gdbstub_debug_exception_entry:
//Save all regs to structure
movi a2, gdbstub_savedRegs
s32i a0, a2, 0x10
s32i a1, a2, 0x58
s32i a1, a2, 0x14
rsr a0, DEBUG_PS
s32i a0, a2, 0x04
rsr a0, DEBUG_EXCSAVE //was R2
s32i a0, a2, 0x14
s32i a3, a2, 0x18
s32i a4, a2, 0x1c
s32i a5, a2, 0x20
s32i a6, a2, 0x24
s32i a7, a2, 0x28
s32i a8, a2, 0x2c
s32i a9, a2, 0x30
s32i a10, a2, 0x34
s32i a11, a2, 0x38
s32i a12, a2, 0x3c
s32i a13, a2, 0x40
s32i a14, a2, 0x44
s32i a15, a2, 0x48
s32i a0, a2, 0x18
s32i a3, a2, 0x1c
s32i a4, a2, 0x20
s32i a5, a2, 0x24
s32i a6, a2, 0x28
s32i a7, a2, 0x2c
s32i a8, a2, 0x30
s32i a9, a2, 0x34
s32i a10, a2, 0x38
s32i a11, a2, 0x3c
s32i a12, a2, 0x40
s32i a13, a2, 0x44
s32i a14, a2, 0x48
s32i a15, a2, 0x4c
rsr a0, SAR
s32i a0, a2, 0x08
rsr a0, LITBASE
s32i a0, a2, 0x4C
rsr a0, 176
s32i a0, a2, 0x50
rsr a0, 208
rsr a0, 176
s32i a0, a2, 0x54
rsr a0, 208
s32i a0, a2, 0x58
rsr a0, DEBUGCAUSE
s32i a0, a2, 0x5C
rsr a4, DEBUG_PC
@ -127,33 +131,33 @@ DebugExceptionExit:
movi a2, gdbstub_savedRegs
l32i a0, a2, 0x00
wsr a0, DEBUG_PC
// l32i a0, a2, 0x54
// l32i a0, a2, 0x58
// wsr a0, 208
l32i a0, a2, 0x50
l32i a0, a2, 0x54
//wsr a0, 176 //Some versions of gcc do not understand this...
.byte 0x00, 176, 0x13 //so we hand-assemble the instruction.
l32i a0, a2, 0x4C
l32i a0, a2, 0x50
wsr a0, LITBASE
l32i a0, a2, 0x08
wsr a0, SAR
l32i a15, a2, 0x48
l32i a14, a2, 0x44
l32i a13, a2, 0x40
l32i a12, a2, 0x3c
l32i a11, a2, 0x38
l32i a10, a2, 0x34
l32i a9, a2, 0x30
l32i a8, a2, 0x2c
l32i a7, a2, 0x28
l32i a6, a2, 0x24
l32i a5, a2, 0x20
l32i a4, a2, 0x1c
l32i a3, a2, 0x18
l32i a0, a2, 0x14
l32i a15, a2, 0x4c
l32i a14, a2, 0x48
l32i a13, a2, 0x44
l32i a12, a2, 0x40
l32i a11, a2, 0x3c
l32i a10, a2, 0x38
l32i a9, a2, 0x34
l32i a8, a2, 0x30
l32i a7, a2, 0x2c
l32i a6, a2, 0x28
l32i a5, a2, 0x24
l32i a4, a2, 0x20
l32i a3, a2, 0x1c
l32i a0, a2, 0x18
wsr a0, DEBUG_EXCSAVE //was R2
l32i a0, a2, 0x04
wsr a0, DEBUG_PS
l32i a1, a2, 0x58
l32i a1, a2, 0x14
l32i a0, a2, 0x10
//Read back vector-saved a2 value, put back address of this routine.
@ -162,8 +166,10 @@ DebugExceptionExit:
//All done. Return to where we came from.
rfi XCHAL_DEBUGLEVEL
.size gdbstub_debug_exception_entry, .-gdbstub_debug_exception_entry
#if GDBSTUB_BREAK_ON_EXCEPTION
#if GDBSTUB_FREERTOS
/*
@ -184,32 +190,34 @@ the user exception handler vector:
*/
.global gdbstub_handle_user_exception
.global gdbstub_user_exception_entry
.type gdbstub_user_exception_entry, @function
ASATTR_GDBFN
.align 4
gdbstub_user_exception_entry:
//Save all regs to structure
movi a0, gdbstub_savedRegs
s32i a1, a0, 0x14 //was a2
s32i a3, a0, 0x18
s32i a4, a0, 0x1c
s32i a5, a0, 0x20
s32i a6, a0, 0x24
s32i a7, a0, 0x28
s32i a8, a0, 0x2c
s32i a9, a0, 0x30
s32i a10, a0, 0x34
s32i a11, a0, 0x38
s32i a12, a0, 0x3c
s32i a13, a0, 0x40
s32i a14, a0, 0x44
s32i a15, a0, 0x48
s32i a1, a0, 0x18 //was a2
s32i a3, a0, 0x1c
s32i a4, a0, 0x20
s32i a5, a0, 0x24
s32i a6, a0, 0x28
s32i a7, a0, 0x2c
s32i a8, a0, 0x30
s32i a9, a0, 0x34
s32i a10, a0, 0x38
s32i a11, a0, 0x3c
s32i a12, a0, 0x40
s32i a13, a0, 0x44
s32i a14, a0, 0x48
s32i a15, a0, 0x4c
rsr a2, SAR
s32i a2, a0, 0x08
rsr a2, LITBASE
s32i a2, a0, 0x4C
rsr a2, 176
s32i a2, a0, 0x50
rsr a2, 208
rsr a2, 176
s32i a2, a0, 0x54
rsr a2, 208
s32i a2, a0, 0x58
rsr a2, EXCCAUSE
s32i a2, a0, 0x5C
@ -243,10 +251,13 @@ is still something we need to implement later, if there's any demand for it, or
FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.)
*/
j UserExceptionExit
.size gdbstub_user_exception_entry, .-gdbstub_user_exception_entry
.global gdbstub_handle_uart_int
.global gdbstub_uart_entry
.type gdbstub_uart_entry, @function
ASATTR_GDBFN
.align 4
gdbstub_uart_entry:
//On entry, the stack frame is at SP+16.
@ -255,29 +266,37 @@ gdbstub_uart_entry:
add a2, a2, a1
movi a3, gdbstub_handle_uart_int
jx a3
.size gdbstub_uart_entry, .-gdbstub_uart_entry
#endif
#endif
.global gdbstub_save_extra_sfrs_for_exception
.type gdbstub_save_extra_sfrs_for_exception, @function
ASATTR_GDBFN
.align 4
//The Xtensa OS HAL does not save all the special function register things. This bit of assembly
//fills the gdbstub_savedRegs struct with them.
gdbstub_save_extra_sfrs_for_exception:
movi a2, gdbstub_savedRegs
rsr a3, LITBASE
s32i a3, a2, 0x4C
rsr a3, 176
s32i a3, a2, 0x50
rsr a3, 208
rsr a3, 176
s32i a3, a2, 0x54
rsr a3, 208
s32i a3, a2, 0x58
rsr a3, EXCCAUSE
s32i a3, a2, 0x5C
ret
.size gdbstub_save_extra_sfrs_for_exception, .-gdbstub_save_extra_sfrs_for_exception
.global gdbstub_init_debug_entry
.global _DebugExceptionVector
.type gdbstub_init_debug_entry, @function
ASATTR_GDBINIT
.align 4
gdbstub_init_debug_entry:
//This puts the following 2 instructions into the debug exception vector:
@ -294,10 +313,13 @@ gdbstub_init_debug_entry:
wsr a2, DEBUG_EXCSAVE
ret
.size gdbstub_init_debug_entry, .-gdbstub_init_debug_entry
//Set up ICOUNT register to step one single instruction
.global gdbstub_icount_ena_single_step
.type gdbstub_icount_ena_single_step, @function
ASATTR_GDBFN
.align 4
gdbstub_icount_ena_single_step:
movi a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode
@ -306,6 +328,7 @@ gdbstub_icount_ena_single_step:
wsr a2, ICOUNT
isync
ret
.size gdbstub_icount_ena_single_step, .-gdbstub_icount_ena_single_step
//These routines all assume only one breakpoint and watchpoint is available, which
@ -313,6 +336,8 @@ gdbstub_icount_ena_single_step:
.global gdbstub_set_hw_breakpoint
.type gdbstub_set_hw_breakpoint, @function
ASATTR_GDBFN
gdbstub_set_hw_breakpoint:
//a2 - addr, a3 - len (unused here)
rsr a4, IBREAKENABLE
@ -323,8 +348,11 @@ gdbstub_set_hw_breakpoint:
isync
movi a2, 1
ret
.size gdbstub_set_hw_breakpoint, .-gdbstub_set_hw_breakpoint
.global gdbstub_del_hw_breakpoint
.type gdbstub_del_hw_breakpoint, @function
ASATTR_GDBFN
gdbstub_del_hw_breakpoint:
//a2 - addr
rsr a5, IBREAKENABLE
@ -336,8 +364,11 @@ gdbstub_del_hw_breakpoint:
isync
movi a2, 1
ret
.size gdbstub_del_hw_breakpoint, .-gdbstub_del_hw_breakpoint
.global gdbstub_set_hw_watchpoint
.type gdbstub_set_hw_watchpoint, @function
ASATTR_GDBFN
//a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access)
gdbstub_set_hw_watchpoint:
//Check if any of the masked address bits are set. If so, that is an error.
@ -362,9 +393,12 @@ gdbstub_set_hw_watchpoint:
mov a2, a3
isync
ret
.size gdbstub_set_hw_watchpoint, .-gdbstub_set_hw_watchpoint
.global gdbstub_del_hw_watchpoint
.type gdbstub_del_hw_watchpoint, @function
ASATTR_GDBFN
//a2 - addr
gdbstub_del_hw_watchpoint:
//See if the address matches
@ -384,11 +418,14 @@ gdbstub_del_hw_watchpoint:
return_w_error:
movi a2, 0
ret
.size gdbstub_del_hw_watchpoint, .-gdbstub_del_hw_watchpoint
//Breakpoint, with an attempt at a functional function prologue and epilogue...
.global gdbstub_do_break_breakpoint_addr
.global gdbstub_do_break
.type gdbstub_do_break, @function
ASATTR_GDBFN
.align 4
gdbstub_do_break:
addi a1, a1, -16
@ -402,3 +439,4 @@ gdbstub_do_break_breakpoint_addr:
l32i a15, a1, 12
addi a1, a1, 16
ret
.size gdbstub_do_break, .-gdbstub_do_break

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
#ifdef __cplusplus
extern "C" {
#endif
void gdbstub_init();
#ifdef __cplusplus
}
#endif
#endif