diff --git a/components/esp32s2beta/CMakeLists.txt b/components/esp32s2beta/CMakeLists.txt index dcd86321f4..27fe95acbb 100644 --- a/components/esp32s2beta/CMakeLists.txt +++ b/components/esp32s2beta/CMakeLists.txt @@ -19,7 +19,6 @@ elseif(CONFIG_IDF_TARGET_ESP32S2BETA) "dport_panic_highint_hdl.S" "esp_adapter.c" "esp_timer_esp32s2beta.c" - "gdbstub.c" "hw_random.c" "int_wdt.c" "intr_alloc.c" diff --git a/components/esp32s2beta/Kconfig b/components/esp32s2beta/Kconfig index 66aa4b1ebb..2f0b70adb7 100644 --- a/components/esp32s2beta/Kconfig +++ b/components/esp32s2beta/Kconfig @@ -317,6 +317,7 @@ menu "ESP32S2-specific" config ESP32S2_PANIC_GDBSTUB bool "Invoke GDBStub" + select ESP_GDBSTUB_ENABLED help Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem of the crash. diff --git a/components/esp32s2beta/gdbstub.c b/components/esp32s2beta/gdbstub.c deleted file mode 100644 index 38d87c0d87..0000000000 --- a/components/esp32s2beta/gdbstub.c +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/****************************************************************************** - * Description: A stub to make the ESP32 debuggable by GDB over the serial - * port, at least enough to do a backtrace on panic. This gdbstub is read-only: - * it allows inspecting the ESP32 state - *******************************************************************************/ - -#include "esp32s2beta/rom/ets_sys.h" -#include "soc/uart_reg.h" -#include "soc/io_mux_reg.h" -#include "esp_private/gdbstub.h" -#include "driver/gpio.h" - -//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which -//implies a minimum size of about 320 bytes. -#define PBUFLEN 512 - -static unsigned char cmd[PBUFLEN]; //GDB command input buffer -static char chsum; //Running checksum of the output packet - -#define ATTR_GDBFN - -//Receive a char from the uart. Uses polling and feeds the watchdog. -static int ATTR_GDBFN gdbRecvChar() { - int i; - while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) ; - i=READ_PERI_REG(UART_FIFO_AHB_REG(0)); - return i; -} - -//Send a char to the uart. -static void ATTR_GDBFN gdbSendChar(char c) { - while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ; - WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c); -} - -//Send the start of a packet; reset checksum calculation. -static void ATTR_GDBFN gdbPacketStart() { - chsum=0; - gdbSendChar('$'); -} - -//Send a char as part of a packet -static void ATTR_GDBFN gdbPacketChar(char c) { - if (c=='#' || c=='$' || c=='}' || c=='*') { - gdbSendChar('}'); - gdbSendChar(c^0x20); - chsum+=(c^0x20)+'}'; - } else { - gdbSendChar(c); - chsum+=c; - } -} - -//Send a string as part of a packet -static void ATTR_GDBFN gdbPacketStr(const char *c) { - while (*c!=0) { - gdbPacketChar(*c); - c++; - } -} - -//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. -static void ATTR_GDBFN gdbPacketHex(int val, int bits) { - char hexChars[]="0123456789abcdef"; - int i; - for (i=bits; i>0; i-=4) { - gdbPacketChar(hexChars[(val>>(i-4))&0xf]); - } -} - -//Finish sending a packet. -static void ATTR_GDBFN gdbPacketEnd() { - gdbSendChar('#'); - gdbPacketHex(chsum, 8); -} - -//Error states used by the routines that grab stuff from the incoming gdb packet -#define ST_ENDPACKET -1 -#define ST_ERR -2 -#define ST_OK -3 -#define ST_CONT -4 - -//Grab a hex value from the gdb packet. Ptr will get positioned on the end -//of the hex string, as far as the routine has read into it. Bits/4 indicates -//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much -//hex chars as possible. -static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { - int i; - int no; - unsigned int v=0; - char c; - no=bits/4; - if (bits==-1) no=64; - for (i=0; i='0' && c<='9') { - v<<=4; - v|=(c-'0'); - } else if (c>='A' && c<='F') { - v<<=4; - v|=(c-'A')+10; - } else if (c>='a' && c<='f') { - v<<=4; - v|=(c-'a')+10; - } else if (c=='#') { - if (bits==-1) { - (*ptr)--; - return v; - } - return ST_ENDPACKET; - } else { - if (bits==-1) { - (*ptr)--; - return v; - } - return ST_ERR; - } - } - return v; -} - -//Swap an int into the form gdb wants it -static int ATTR_GDBFN iswap(int i) { - int r; - r=((i>>24)&0xff); - r|=((i>>16)&0xff)<<8; - r|=((i>>8)&0xff)<<16; - r|=((i>>0)&0xff)<<24; - return r; -} - -//Read a byte from ESP32 memory. -static unsigned char ATTR_GDBFN readbyte(unsigned int p) { - int *i=(int*)(p&(~3)); - if (p<0x20000000 || p>=0x80000000) return -1; - return *i>>((p&3)*8); -} - - -//Register file in the format exp108 gdb port expects it. -//Inspired by gdb/regformats/reg-xtensa.dat -typedef struct { - uint32_t pc; - uint32_t a[64]; - uint32_t lbeg; - uint32_t lend; - uint32_t lcount; - uint32_t sar; - uint32_t windowbase; - uint32_t windowstart; - uint32_t configid0; - uint32_t configid1; - uint32_t ps; - uint32_t threadptr; - uint32_t br; - uint32_t scompare1; - uint32_t acclo; - uint32_t acchi; - uint32_t m0; - uint32_t m1; - uint32_t m2; - uint32_t m3; - uint32_t expstate; //I'm going to assume this is exccause... - uint32_t f64r_lo; - uint32_t f64r_hi; - uint32_t f64s; - uint32_t f[16]; - uint32_t fcr; - uint32_t fsr; -} GdbRegFile; - - -GdbRegFile gdbRegFile; - -/* -//Register format as the Xtensa HAL has it: -STRUCT_FIELD (long, 4, XT_STK_EXIT, exit) -STRUCT_FIELD (long, 4, XT_STK_PC, pc) -STRUCT_FIELD (long, 4, XT_STK_PS, ps) -STRUCT_FIELD (long, 4, XT_STK_A0, a0) -[..] -STRUCT_FIELD (long, 4, XT_STK_A15, a15) -STRUCT_FIELD (long, 4, XT_STK_SAR, sar) -STRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause) -STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) -STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) -STRUCT_FIELD (long, 4, XT_STK_LEND, lend) -STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) -// Temporary space for saving stuff during window spill -STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0) -STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1) -STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2) -STRUCT_FIELD (long, 4, XT_STK_VPRI, vpri) -STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly) -#endif -STRUCT_END(XtExcFrame) -*/ - - -static void dumpHwToRegfile(XtExcFrame *frame) { - int i; - long *frameAregs=&frame->a0; - gdbRegFile.pc=frame->pc; - for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i]; - for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF; - gdbRegFile.sar=frame->sar; - //All windows have been spilled to the stack by the ISR routines. The following values should indicate that. - gdbRegFile.sar=frame->sar; - gdbRegFile.windowbase=0; //0 - gdbRegFile.windowstart=0x1; //1 - gdbRegFile.configid0=0xdeadbeef; //ToDo - gdbRegFile.configid1=0xdeadbeef; //ToDo - gdbRegFile.ps=frame->ps-PS_EXCM_MASK; - gdbRegFile.threadptr=0xdeadbeef; //ToDo - gdbRegFile.br=0xdeadbeef; //ToDo - gdbRegFile.scompare1=0xdeadbeef; //ToDo - gdbRegFile.acclo=0xdeadbeef; //ToDo - gdbRegFile.acchi=0xdeadbeef; //ToDo - gdbRegFile.m0=0xdeadbeef; //ToDo - gdbRegFile.m1=0xdeadbeef; //ToDo - gdbRegFile.m2=0xdeadbeef; //ToDo - gdbRegFile.m3=0xdeadbeef; //ToDo - gdbRegFile.expstate=frame->exccause; //ToDo -} - - -//Send the reason execution is stopped to GDB. -static void sendReason() { - //exception-to-signal mapping - char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7}; - int i=0; - gdbPacketStart(); - gdbPacketChar('T'); - i=gdbRegFile.expstate&0x7f; - if (i=PBUFLEN) return ST_ERR; - } - //A # has been received. Get and check the received chsum. - sentchs[0]=gdbRecvChar(); - sentchs[1]=gdbRecvChar(); - ptr=&sentchs[0]; - rchsum=gdbGetHexVal(&ptr, 8); - if (rchsum!=chsum) { - gdbSendChar('-'); - return ST_ERR; - } else { - gdbSendChar('+'); - return gdbHandleCommand(cmd, p); - } -} - - - -void esp_gdbstub_panic_handler(XtExcFrame *frame) { - dumpHwToRegfile(frame); - //Make sure txd/rxd are enabled - gpio_pullup_dis(1); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); - - sendReason(); - while(gdbReadCommand()!=ST_CONT); - while(1); -} - diff --git a/components/esp_gdbstub/esp32s2beta/gdbstub_esp32s2beta.c b/components/esp_gdbstub/esp32s2beta/gdbstub_esp32s2beta.c new file mode 100644 index 0000000000..7bf60cf702 --- /dev/null +++ b/components/esp_gdbstub/esp32s2beta/gdbstub_esp32s2beta.c @@ -0,0 +1,51 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/uart_periph.h" +#include "soc/gpio_periph.h" +#include "esp_gdbstub_common.h" +#include "sdkconfig.h" + +#define UART_NUM CONFIG_ESP_CONSOLE_UART_NUM + +void esp_gdbstub_target_init() +{ +} + +int esp_gdbstub_getchar() +{ + while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_RXFIFO_CNT) == 0) { + ; + } + return REG_READ(UART_FIFO_AHB_REG(UART_NUM)); +} + +void esp_gdbstub_putchar(int c) +{ + while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_TXFIFO_CNT) >= 126) { + ; + } + REG_WRITE(UART_FIFO_AHB_REG(UART_NUM), c); +} + +int esp_gdbstub_readmem(intptr_t addr) +{ + if (addr < 0x20000000 || addr >= 0x80000000) { + /* see cpu_configure_region_protection */ + return -1; + } + uint32_t val_aligned = *(uint32_t *)(addr & (~3)); + uint32_t shift = (addr & 3) * 8; + return (val_aligned >> shift) & 0xff; +} diff --git a/components/esp_gdbstub/esp32s2beta/gdbstub_target_config.h b/components/esp_gdbstub/esp32s2beta/gdbstub_target_config.h new file mode 100644 index 0000000000..0b15671ea1 --- /dev/null +++ b/components/esp_gdbstub/esp32s2beta/gdbstub_target_config.h @@ -0,0 +1,18 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +/* Number of extra TIE defined registers, not listed in the XCHAL */ +#define GDBSTUB_EXTRA_TIE_SIZE 1 diff --git a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c index 853b1ba085..edae3226f8 100644 --- a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c +++ b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c @@ -18,6 +18,7 @@ #include "soc/cpu.h" #include "soc/soc_memory_layout.h" #include "sdkconfig.h" +#include "esp_debug_helpers.h" #if !XCHAL_HAVE_WINDOWED #warning "gdbstub_xtensa: revisit the implementation for Call0 ABI"