From 7bb91f912c672b34ff6b23fecdd6f86368c63a8d Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Apr 2021 10:52:09 +0300 Subject: [PATCH 1/5] gdbstub component --- components/driver/uart.c | 3 + components/esp_gdbstub/CMakeLists.txt | 21 +- components/esp_gdbstub/esp32/gdbstub_esp32.c | 38 --- .../esp_gdbstub/esp32s2/gdbstub_esp32s2.c | 38 --- .../esp_gdbstub/esp32s3/gdbstub_esp32s3.c | 37 --- .../esp_gdbstub/esp_common/gdbstub_common.c | 129 +++++++++ components/esp_gdbstub/include/esp_gdbstub.h | 4 +- .../private_include/esp_gdbstub_common.h | 19 +- components/esp_gdbstub/src/gdbstub.c | 268 ++++++++++++++++-- components/esp_gdbstub/src/packet.c | 6 +- components/esp_gdbstub/xtensa/gdbstub-entry.S | 44 +++ .../esp_gdbstub/xtensa/gdbstub_xtensa.c | 1 - components/esp_system/Kconfig | 10 +- docs/en/api-guides/tools/idf-monitor.rst | 12 +- .../hello_world/main/CMakeLists.txt | 2 +- examples/system/gdbstub/CMakeLists.txt | 6 + examples/system/gdbstub/Makefile | 9 + examples/system/gdbstub/README.md | 127 +++++++++ examples/system/gdbstub/main/CMakeLists.txt | 2 + examples/system/gdbstub/main/component.mk | 5 + examples/system/gdbstub/main/gdbstub_main.c | 39 +++ examples/system/gdbstub/sdkconfig.defaults | 22 ++ 22 files changed, 681 insertions(+), 161 deletions(-) create mode 100644 components/esp_gdbstub/esp_common/gdbstub_common.c create mode 100644 components/esp_gdbstub/xtensa/gdbstub-entry.S create mode 100644 examples/system/gdbstub/CMakeLists.txt create mode 100644 examples/system/gdbstub/Makefile create mode 100644 examples/system/gdbstub/README.md create mode 100644 examples/system/gdbstub/main/CMakeLists.txt create mode 100644 examples/system/gdbstub/main/component.mk create mode 100644 examples/system/gdbstub/main/gdbstub_main.c create mode 100644 examples/system/gdbstub/sdkconfig.defaults diff --git a/components/driver/uart.c b/components/driver/uart.c index bf21ac3f80..a8f37eb3a3 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -1319,6 +1319,9 @@ esp_err_t uart_flush_input(uart_port_t uart_num) esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags) { esp_err_t r; +#ifdef CONFIG_ESP_GDBSTUB_ENABLED + UART_CHECK((uart_num != CONFIG_ESP_CONSOLE_UART_NUM), "UART used by GDB-stubs! Please disable GDB in menuconfig.", ESP_FAIL); +#endif // CONFIG_ESP_GDBSTUB_ENABLED UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((rx_buffer_size > SOC_UART_FIFO_LEN), "uart rx buffer length error", ESP_FAIL); UART_CHECK((tx_buffer_size > SOC_UART_FIFO_LEN) || (tx_buffer_size == 0), "uart tx buffer length error", ESP_FAIL); diff --git a/components/esp_gdbstub/CMakeLists.txt b/components/esp_gdbstub/CMakeLists.txt index 0d64fc4465..cb799481b3 100644 --- a/components/esp_gdbstub/CMakeLists.txt +++ b/components/esp_gdbstub/CMakeLists.txt @@ -1,16 +1,15 @@ idf_build_get_property(target IDF_TARGET) -idf_component_register(SRCS "src/gdbstub.c" "src/packet.c" +set(esp_gdbstub_srcs "src/gdbstub.c" + "src/packet.c" + "esp_common/gdbstub_common.c" + "${target}/gdbstub_${target}.c" + "xtensa/gdbstub-entry.S" + "xtensa/gdbstub_xtensa.c") + +idf_component_register(SRCS "${esp_gdbstub_srcs}" INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" "${target}" "xtensa" LDFRAGMENTS "linker.lf" REQUIRES "freertos" - PRIV_REQUIRES "soc" "esp_rom") - -if(CONFIG_IDF_TARGET_ARCH_XTENSA) - target_include_directories(${COMPONENT_LIB} PUBLIC "xtensa" "${target}") - target_sources(${COMPONENT_LIB} PRIVATE "xtensa/gdbstub_xtensa.c" "${target}/gdbstub_${target}.c") -elseif(CONFIG_IDF_TARGET_ARCH_RISCV) - target_include_directories(${COMPONENT_LIB} PUBLIC "riscv" "${target}") - target_sources(${COMPONENT_LIB} PRIVATE "riscv/gdbstub_riscv.c" "${target}/gdbstub_${target}.c") -endif() + PRIV_REQUIRES "soc" "xtensa" "esp_rom") diff --git a/components/esp_gdbstub/esp32/gdbstub_esp32.c b/components/esp_gdbstub/esp32/gdbstub_esp32.c index 2397a3940e..39fde0a6c7 100644 --- a/components/esp_gdbstub/esp32/gdbstub_esp32.c +++ b/components/esp_gdbstub/esp32/gdbstub_esp32.c @@ -16,41 +16,3 @@ #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(void) -{ -} - -int esp_gdbstub_getchar(void) -{ - while (REG_GET_FIELD(UART_STATUS_REG(UART_NUM), UART_RXFIFO_CNT) == 0) { - ; - } - return REG_READ(UART_FIFO_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_REG(UART_NUM), c); -} - -void esp_gdbstub_flush() -{ - //not needed for uart -} - -int esp_gdbstub_readmem(intptr_t addr) -{ - if (addr < 0x20000000 || addr >= 0x80000000) { - /* see esp_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/esp32s2/gdbstub_esp32s2.c b/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c index 8ac52d4083..39fde0a6c7 100644 --- a/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c +++ b/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c @@ -16,41 +16,3 @@ #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); -} - -void esp_gdbstub_flush() -{ - //not needed for uart -} - -int esp_gdbstub_readmem(intptr_t addr) -{ - if (addr < 0x20000000 || addr >= 0x80000000) { - /* see esp_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/esp32s3/gdbstub_esp32s3.c b/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c index 6c2eb40717..1e02fec0d0 100644 --- a/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c +++ b/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c @@ -17,40 +17,3 @@ #include "soc/gpio_periph.h" #include "esp_gdbstub_common.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); -} - -void esp_gdbstub_flush() -{ - //not needed for uart -} - -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/esp_common/gdbstub_common.c b/components/esp_gdbstub/esp_common/gdbstub_common.c new file mode 100644 index 0000000000..23ff278a2c --- /dev/null +++ b/components/esp_gdbstub/esp_common/gdbstub_common.c @@ -0,0 +1,129 @@ +// 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" +#include "hal/uart_ll.h" + +#define UART_NUM CONFIG_ESP_CONSOLE_UART_NUM + +static uart_dev_t *gdb_uart = NULL; + + +void esp_gdbstub_target_init(void) +{ + switch (UART_NUM) { + case 0: + gdb_uart = &UART0; + break; + case 1: + gdb_uart = &UART1; + break; + case 2: + gdb_uart = &UART2; + break; + default: + gdb_uart = &UART0; + break; + } +} + +int esp_gdbstub_getchar(void) +{ + if (gdb_uart == NULL) { + esp_gdbstub_target_init(); + } + unsigned char data; + while (uart_ll_get_rxfifo_len(gdb_uart) == 0) { + + } + uart_ll_read_rxfifo(gdb_uart, &data, 1); + return data; +} + +void esp_gdbstub_putchar(int c) +{ + if (gdb_uart == NULL) { + esp_gdbstub_target_init(); + } + while (uart_ll_get_txfifo_len(gdb_uart) <= 126) { + } + uart_ll_write_txfifo(gdb_uart, (uint8_t *)&c, 1); +} + +void esp_gdbstub_flush() +{ + //not needed for uart +} + +int esp_gdbstub_getfifo() +{ + if (gdb_uart == NULL) { + esp_gdbstub_target_init(); + } + int doDebug = 0; + + int fifolen = uart_ll_get_rxfifo_len(gdb_uart); + while (fifolen != 0) { + unsigned char data; + uart_ll_read_rxfifo(gdb_uart, &data, 1); + if (data == 0x3) { + doDebug = 1; //Check if any of the chars is Ctrl+C. Throw away rest. + } + if (data == '+') { + doDebug = 1; //Check if any of the chars is '+'. Throw away rest. + } + fifolen--; + } + uart_ll_clr_intsts_mask(gdb_uart, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT); + return doDebug; +} + +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; +} + +int esp_gdbstub_writemem(unsigned int addr, unsigned char data) +{ + if (addr < 0x20000000 || addr >= 0x80000000) { + /* see cpu_configure_region_protection */ + return -1; + } + + int *i = (int *)(addr & (~3)); + if ((addr & 3) == 0) { + *i = (*i & 0xffffff00) | (data << 0); + } + if ((addr & 3) == 1) { + *i = (*i & 0xffff00ff) | (data << 8); + } + if ((addr & 3) == 2) { + *i = (*i & 0xff00ffff) | (data << 16); + } + if ((addr & 3) == 3) { + *i = (*i & 0x00ffffff) | (data << 24); + } + asm volatile("ISYNC\nISYNC\n"); + + return 0; +} \ No newline at end of file diff --git a/components/esp_gdbstub/include/esp_gdbstub.h b/components/esp_gdbstub/include/esp_gdbstub.h index 02fda63e58..d896e77ffc 100644 --- a/components/esp_gdbstub/include/esp_gdbstub.h +++ b/components/esp_gdbstub/include/esp_gdbstub.h @@ -14,13 +14,11 @@ #pragma once -#include "esp_gdbstub_arch.h" - #ifdef __cplusplus extern "C" { #endif -void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) __attribute__((noreturn)); +void esp_gdbstub_init(void); #ifdef __cplusplus } diff --git a/components/esp_gdbstub/private_include/esp_gdbstub_common.h b/components/esp_gdbstub/private_include/esp_gdbstub_common.h index 666e75aedb..cb3d341c32 100644 --- a/components/esp_gdbstub/private_include/esp_gdbstub_common.h +++ b/components/esp_gdbstub/private_include/esp_gdbstub_common.h @@ -18,7 +18,7 @@ #include #include -#include "esp_gdbstub.h" +#include "esp_gdbstub_arch.h" #include "sdkconfig.h" #ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS @@ -30,6 +30,7 @@ #define GDBSTUB_ST_ENDPACKET -1 #define GDBSTUB_ST_ERR -2 #define GDBSTUB_ST_OK -3 +#define GDBSTUB_ST_CONT -4 /* Special task index values */ #define GDBSTUB_CUR_TASK_INDEX_UNKNOWN -1 @@ -125,6 +126,20 @@ int esp_gdbstub_readmem(intptr_t addr); */ void esp_gdbstub_flush(void); +/** + * Write a byte to target memory + * @param addr address + * @param data data byte + * @return 0 in case of success, -1 in case of error + */ +int esp_gdbstub_writemem(unsigned int addr, unsigned char data); + +/** + * Read a data from fifo and detect start symbol + * @return 1 if break symbol was detected, or 0 if not + */ +int esp_gdbstub_getfifo(void); + /**** GDB packet related functions ****/ /** Begin a packet */ @@ -143,7 +158,7 @@ void esp_gdbstub_send_hex(int val, int bits); void esp_gdbstub_send_end(void); /** Send a packet with a string as content */ -void esp_gdbstub_send_str_packet(const char* str); +void esp_gdbstub_send_str_packet(const char *str); /** Get a hex value from the gdb packet */ uint32_t esp_gdbstub_gethex(const unsigned char **ptr, int bits); diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index 6e0a800069..b58fec135e 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -17,6 +17,15 @@ #include "esp_gdbstub_common.h" #include "sdkconfig.h" +#include "soc/uart_reg.h" +#include "soc/periph_defs.h" +#include "esp_attr.h" +#include "esp_intr_alloc.h" +#include "hal/wdt_hal.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +//#include "esp_task_wdt.h" + #ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS static inline int gdb_tid_to_task_index(int tid); @@ -25,14 +34,17 @@ static void init_task_info(void); static void find_paniced_task_index(void); static void set_active_task(size_t index); static int handle_task_commands(unsigned char *cmd, int len); +static void esp_gdbstub_send_str_as_hex(const char *str); #endif static void send_reason(void); - static esp_gdbstub_scratch_t s_scratch; +static esp_gdbstub_gdb_regfile_t *gdb_local_regfile = &s_scratch.regfile; - +/** + * @breef panic handler +*/ void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) { #ifndef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS @@ -80,7 +92,9 @@ void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) } } - +/** + * Set interrupt reason to GDB +*/ static void send_reason(void) { esp_gdbstub_send_start(); @@ -89,13 +103,159 @@ static void send_reason(void) esp_gdbstub_send_end(); } +/** + * Swap bytes in word +*/ static uint32_t gdbstub_hton(uint32_t i) { return __builtin_bswap32(i); } +static wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; +static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; +static wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + +static bool wdt0_context_enabled = false; +static bool wdt1_context_enabled = false; +static bool rtc_wdt_ctx_enabled = false; +/** + * Disable all enabled WDTs + */ +static inline void disable_all_wdts(void) +{ + wdt0_context_enabled = wdt_hal_is_enabled(&wdt0_context); + wdt1_context_enabled = wdt_hal_is_enabled(&wdt1_context); + rtc_wdt_ctx_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); + + //Task WDT is the Main Watchdog Timer of Timer Group 0 + if (true == wdt0_context_enabled) { + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_feed(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + } + + //Interupt WDT is the Main Watchdog Timer of Timer Group 1 + if (true == wdt1_context_enabled) { + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_feed(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + } + if (true == rtc_wdt_ctx_enabled) { + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + } +} + +/** + * Enable all enabled WDTs + */ +static inline void enable_all_wdts(void) +{ + //Task WDT is the Main Watchdog Timer of Timer Group 0 + if (false == wdt0_context_enabled) { + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_enable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + } + // Interupt WDT is the Main Watchdog Timer of Timer Group 1 + if (false == wdt1_context_enabled) { + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_enable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); + } + + if (false == rtc_wdt_ctx_enabled) { + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + } +} + +/** + * @breef Handle UART interrupt + * + * Handle UART interrupt for gdbstub. The function disable WDT. + * If Ctrl+C combination detected (0x03), then application will start to process incoming GDB messages. + * The gdbstub will stay in this interrupt until continue command will be received ($c#63). + * + * @param curr_regs - actual registers frame + * +*/ +void gdbstub_handle_uart_int(XtExcFrame *regs_frame) +{ + // Disable all enabled WDT on enter + disable_all_wdts(); + + int doDebug = esp_gdbstub_getfifo(); + s_scratch.signal = esp_gdbstub_get_signal(regs_frame); + + if (doDebug) { +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + init_task_info(); +#endif// CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + esp_gdbstub_frame_to_regfile(regs_frame, gdb_local_regfile); + send_reason(); + while (true) { + unsigned char *cmd; + size_t size; + + int res = esp_gdbstub_read_command(&cmd, &size); + if (res == '-') { + send_reason(); + continue; + } + if (res > 0) { + /* character received instead of a command */ + continue; + } + if (res == -2) { + esp_gdbstub_send_str_packet("E01"); + continue; + } + res = esp_gdbstub_handle_command(cmd, size); + if (res == -2) { + esp_gdbstub_send_str_packet(NULL); + } +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + if (res == GDBSTUB_ST_CONT) { + break; + } +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + } + } +} + +intr_handle_t intr_handle_; +extern void _xt_gdbstub_int(void * ); + +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +/** @breef Init gdbstub + * Init uart interrupt for gdbstub + * */ +void esp_gdbstub_init(void) +{ + esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, _xt_gdbstub_int, NULL, &intr_handle_); +} +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + +#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + +/** Send string as a het to uart */ +static void esp_gdbstub_send_str_as_hex(const char *str) +{ + while (*str) { + esp_gdbstub_send_hex(*str, 8); + str++; + } +} +#endif + /** Send all registers to gdb */ -static void handle_g_command(const unsigned char* cmd, int len) +static void handle_g_command(const unsigned char *cmd, int len) { uint32_t *p = (uint32_t *) &s_scratch.regfile; esp_gdbstub_send_start(); @@ -106,7 +266,7 @@ static void handle_g_command(const unsigned char* cmd, int len) } /** Receive register values from gdb */ -static void handle_G_command(const unsigned char* cmd, int len) +static void handle_G_command(const unsigned char *cmd, int len) { uint32_t *p = (uint32_t *) &s_scratch.regfile; for (int i = 0; i < sizeof(s_scratch.regfile) / sizeof(*p); ++i) { @@ -116,7 +276,7 @@ static void handle_G_command(const unsigned char* cmd, int len) } /** Read memory to gdb */ -static void handle_m_command(const unsigned char* cmd, int len) +static void handle_m_command(const unsigned char *cmd, int len) { intptr_t addr = (intptr_t) esp_gdbstub_gethex(&cmd, -1); cmd++; @@ -135,12 +295,32 @@ static void handle_m_command(const unsigned char* cmd, int len) esp_gdbstub_send_end(); } +/** Write memory from gdb */ +static void handle_M_command(const unsigned char *cmd, int len) +{ + intptr_t addr = (intptr_t) esp_gdbstub_gethex(&cmd, -1); + cmd++; // skip '.' + uint32_t size = esp_gdbstub_gethex(&cmd, -1); + cmd++; // skip ':' + + if (esp_gdbstub_readmem(addr) < 0 || esp_gdbstub_readmem(addr + size - 1) < 0) { + esp_gdbstub_send_str_packet("E01"); + return; + } + for (int k = 0; k < size; k++) { + esp_gdbstub_writemem(addr, esp_gdbstub_gethex(&cmd, 8)); + addr++; + } + esp_gdbstub_send_start(); + esp_gdbstub_send_str_packet("OK"); + esp_gdbstub_send_end(); +} + /** Handle a command received from gdb */ int esp_gdbstub_handle_command(unsigned char *cmd, int len) { unsigned char *data = cmd + 1; - if (cmd[0] == 'g') - { + if (cmd[0] == 'g') { handle_g_command(data, len - 1); } else if (cmd[0] == 'G') { /* receive content for all registers from gdb */ @@ -148,6 +328,9 @@ int esp_gdbstub_handle_command(unsigned char *cmd, int len) } else if (cmd[0] == 'm') { /* read memory to gdb */ handle_m_command(data, len - 1); + } else if (cmd[0] == 'M') { + /* write to memory from GDB */ + handle_M_command(data, len - 1); } else if (cmd[0] == '?') { /* Reply with stop reason */ send_reason(); @@ -155,6 +338,8 @@ int esp_gdbstub_handle_command(unsigned char *cmd, int len) } else if (s_scratch.state != GDBSTUB_TASK_SUPPORT_DISABLED) { return handle_task_commands(cmd, len); #endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + } else if (strncmp((char *)cmd, "vCont;c", 7) == 0 || cmd[0] == 'c') { //continue execution + return GDBSTUB_ST_CONT; } else { /* Unrecognized command */ return GDBSTUB_ST_ERR; @@ -209,10 +394,22 @@ static bool get_task_handle(size_t index, TaskHandle_t *handle) return true; } +static eTaskState get_task_state(size_t index) +{ + return eSuspended; +// return s_scratch.tasks[index].eCurrentState; +} + +static int get_task_cpu_id(size_t index) +{ + return 0; + // return s_scratch.tasks[index].xCoreID; +} + /** Get the index of the task running on the current CPU, and save the result */ static void find_paniced_task_index(void) { - TaskHandle_t cur_handle = xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); + TaskHandle_t cur_handle = (TaskHandle_t)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID()); TaskHandle_t handle; for (int i = 0; i < s_scratch.task_count; i++) { if (get_task_handle(i, &handle) && cur_handle == handle) { @@ -244,7 +441,7 @@ static void set_active_task(size_t index) } /** H command sets the "current task" for the purpose of further commands */ -static void handle_H_command(const unsigned char* cmd, int len) +static void handle_H_command(const unsigned char *cmd, int len) { const char *ret = "OK"; if (cmd[1] == 'g') { @@ -270,7 +467,7 @@ static void handle_H_command(const unsigned char* cmd, int len) } /** qC returns the current thread ID */ -static void handle_qC_command(const unsigned char* cmd, int len) +static void handle_qC_command(const unsigned char *cmd, int len) { esp_gdbstub_send_start(); esp_gdbstub_send_str("QC"); @@ -282,7 +479,7 @@ static void handle_qC_command(const unsigned char* cmd, int len) * Since GDB isn't going to ask about the tasks which haven't been listed by q*ThreadInfo, * and the state of tasks can not change (no stepping allowed), simply return "OK" here. */ -static void handle_T_command(const unsigned char* cmd, int len) +static void handle_T_command(const unsigned char *cmd, int len) { esp_gdbstub_send_str_packet("OK"); } @@ -299,14 +496,14 @@ static void send_single_thread_info(int task_index) /** qfThreadInfo requests the start of the thread list, qsThreadInfo (below) is repeated to * get the subsequent threads. */ -static void handle_qfThreadInfo_command(const unsigned char* cmd, int len) +static void handle_qfThreadInfo_command(const unsigned char *cmd, int len) { assert(s_scratch.task_count > 0); /* There should be at least one task */ send_single_thread_info(0); s_scratch.thread_info_index = 1; } -static void handle_qsThreadInfo_command(const unsigned char* cmd, int len) +static void handle_qsThreadInfo_command(const unsigned char *cmd, int len) { int task_index = s_scratch.thread_info_index; if (task_index == s_scratch.task_count) { @@ -319,7 +516,7 @@ static void handle_qsThreadInfo_command(const unsigned char* cmd, int len) } /** qThreadExtraInfo requests the thread name */ -static void handle_qThreadExtraInfo_command(const unsigned char* cmd, int len) +static void handle_qThreadExtraInfo_command(const unsigned char *cmd, int len) { cmd += sizeof("qThreadExtraInfo,") - 1; int task_index = gdb_tid_to_task_index(esp_gdbstub_gethex(&cmd, -1)); @@ -329,19 +526,41 @@ static void handle_qThreadExtraInfo_command(const unsigned char* cmd, int len) return; } esp_gdbstub_send_start(); - const char* task_name = pcTaskGetTaskName(handle); - while (*task_name) { - esp_gdbstub_send_hex(*task_name, 8); - task_name++; + esp_gdbstub_send_str_as_hex("Name: "); + esp_gdbstub_send_str_as_hex((const char *)pcTaskGetTaskName(handle)); + esp_gdbstub_send_hex(' ', 8); + + eTaskState state = get_task_state(task_index); + switch (state) { + case eRunning: + esp_gdbstub_send_str_as_hex("State: Running "); + esp_gdbstub_send_str_as_hex("@CPU"); + esp_gdbstub_send_hex(get_task_cpu_id(task_index) + '0', 8); + break; + case eReady: + esp_gdbstub_send_str_as_hex("State: Ready"); + break; + case eBlocked: + esp_gdbstub_send_str_as_hex("State: Blocked"); + break; + case eSuspended: + esp_gdbstub_send_str_as_hex("State: Suspended"); + break; + case eDeleted: + esp_gdbstub_send_str_as_hex("State: Deleted"); + break; + default: + esp_gdbstub_send_str_as_hex("State: Invalid"); + break; } - /** TODO: add "Running" or "Suspended" and "CPU0" or "CPU1" */ + esp_gdbstub_send_end(); } -bool command_name_matches(const char* pattern, const unsigned char* ucmd, int len) +bool command_name_matches(const char *pattern, const unsigned char *ucmd, int len) { - const char* cmd = (const char*) ucmd; - const char* end = cmd + len; + const char *cmd = (const char *) ucmd; + const char *end = cmd + len; for (; *pattern && cmd < end; ++cmd, ++pattern) { if (*pattern == '?') { continue; @@ -375,6 +594,8 @@ static int handle_task_commands(unsigned char *cmd, int len) /* Unrecognized command */ return GDBSTUB_ST_ERR; } + } else if (strncmp((char *)cmd, "vCont;c", 7) == 0 || cmd[0] == 'c') { //continue execution + return GDBSTUB_ST_CONT; } else { /* Unrecognized command */ return GDBSTUB_ST_ERR; @@ -383,3 +604,4 @@ static int handle_task_commands(unsigned char *cmd, int len) } #endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS + diff --git a/components/esp_gdbstub/src/packet.c b/components/esp_gdbstub/src/packet.c index 9863bff8a9..a3ab60d6db 100644 --- a/components/esp_gdbstub/src/packet.c +++ b/components/esp_gdbstub/src/packet.c @@ -53,7 +53,7 @@ void esp_gdbstub_send_str(const char *c) // 'bits'/4 dictates the number of hex chars sent. void esp_gdbstub_send_hex(int val, int bits) { - const char* hex_chars = "0123456789abcdef"; + const char *hex_chars = "0123456789abcdef"; for (int i = bits; i > 0; i -= 4) { esp_gdbstub_send_char(hex_chars[(val >> (i - 4)) & 0xf]); } @@ -68,7 +68,7 @@ void esp_gdbstub_send_end(void) } // Send a packet with a string as content -void esp_gdbstub_send_str_packet(const char* str) +void esp_gdbstub_send_str_packet(const char *str) { esp_gdbstub_send_start(); if (str != NULL) { @@ -164,7 +164,7 @@ int esp_gdbstub_read_command(unsigned char **out_cmd, size_t *out_size) // A # has been received. Get and check the received chsum. sentchs[0] = esp_gdbstub_getchar(); sentchs[1] = esp_gdbstub_getchar(); - const unsigned char* c_ptr = &sentchs[0]; + const unsigned char *c_ptr = &sentchs[0]; unsigned char rchsum = esp_gdbstub_gethex(&c_ptr, 8); if (rchsum != chsum) { esp_gdbstub_putchar('-'); diff --git a/components/esp_gdbstub/xtensa/gdbstub-entry.S b/components/esp_gdbstub/xtensa/gdbstub-entry.S new file mode 100644 index 0000000000..780eed9967 --- /dev/null +++ b/components/esp_gdbstub/xtensa/gdbstub-entry.S @@ -0,0 +1,44 @@ +#include "freertos/xtensa_rtos.h" + +// ------------------------------------------------ + .section .iram1,"ax" + + .global gdbstub_handle_uart_int + .global _xt_gdbstub_int + .align 4 + +_xt_gdbstub_int: + + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 /* for debug backtrace */ + #endif + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 /* for debug backtrace */ + #endif + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + + /* Save exc cause and vaddr into exception frame */ + rsr a0, EXCCAUSE + s32i a0, sp, XT_STK_EXCCAUSE + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + + /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */ + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + + s32i a0, sp, XT_STK_A0 + + mov a6,sp + call0 gdbstub_handle_uart_int + ret + diff --git a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c index cf8614ac5c..9640a574de 100644 --- a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c +++ b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c @@ -13,7 +13,6 @@ // limitations under the License. #include -#include "esp_gdbstub.h" #include "esp_gdbstub_common.h" #include "soc/cpu.h" #include "soc/soc_memory_layout.h" diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 21e4056dcd..398bafa026 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -26,11 +26,19 @@ menu "ESP System Settings" Just resets the processor without outputting anything config ESP_SYSTEM_PANIC_GDBSTUB - bool "Invoke GDBStub" + bool "GDBStub on panic" 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. + + config ESP_SYSTEM_GDBSTUB_RUNTIME + bool "GDBStub at runtime" + select FREERTOS_UNICORE + select ESP_GDBSTUB_ENABLED + help + Invoke gdbstub on the serial port, allowing for gdb to attach to it and to do a debug on runtime. + This feature will switch system to single core mode. endchoice config ESP_SYSTEM_SINGLE_CORE_MODE diff --git a/docs/en/api-guides/tools/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index c689f5a1ca..cec09371ad 100644 --- a/docs/en/api-guides/tools/idf-monitor.rst +++ b/docs/en/api-guides/tools/idf-monitor.rst @@ -59,7 +59,10 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t * - * Ctrl+X (or X) - Exit the program - - + * - Ctrl+] + - Interrupt running application + - Pauses IDF monitor and run GDB_ project debugger to debug the application at runtime. + Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the serial port. @@ -186,17 +189,20 @@ Launching GDB with GDBStub By default, if esp-idf crashes, the panic handler prints relevant registers and the stack dump (similar to the ones above) over the serial port. Then it resets the board. +Furthermore, the application can be configured to run GDBStub in the background and handle the Ctrl+C event from the monitor. + Optionally, the panic handler can be configured to run GDBStub, the tool which can communicate with GDB_ project debugger. GDBStub allows to read memory, examine call stack frames and variables, etc. It is not as versatile as JTAG debugging, but this method does not require any special hardware. -To enable GDBStub, open the project configuration menu (``idf.py menuconfig``) and set :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``Invoke GDBStub``. +To enable GDBStub on panic, open the project configuration menu (``idf.py menuconfig``) and set :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``GDBStub on panic`` or set :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``GDBStub on runtime``. -In this case, if the panic handler is triggered, as soon as IDF Monitor sees that GDBStub has loaded, it automatically pauses serial monitoring and runs GDB with necessary arguments. After GDB exits, the board is reset via the RTS serial line. If this line is not connected, please reset the board manually by pressing its Reset button. +In this case, if the panic handler or Ctrl+C command is triggered, as soon as IDF Monitor sees that GDBStub has loaded, it automatically pauses serial monitoring and runs GDB with necessary arguments. After GDB exits, the board is reset via the RTS serial line. If this line is not connected, please reset the board manually by pressing its Reset button. In the background, IDF Monitor runs the following command:: {IDF_TARGET_TOOLCHAIN_PREFIX}-gdb -ex "set serial baud BAUD" -ex "target remote PORT" -ex interrupt build/PROJECT.elf :idf_target:`Hello NAME chip` + Output Filtering ~~~~~~~~~~~~~~~~ diff --git a/examples/get-started/hello_world/main/CMakeLists.txt b/examples/get-started/hello_world/main/CMakeLists.txt index 07686dc8e1..c299e03782 100644 --- a/examples/get-started/hello_world/main/CMakeLists.txt +++ b/examples/get-started/hello_world/main/CMakeLists.txt @@ -1,2 +1,2 @@ idf_component_register(SRCS "hello_world_main.c" - INCLUDE_DIRS "") + INCLUDE_DIRS "") \ No newline at end of file diff --git a/examples/system/gdbstub/CMakeLists.txt b/examples/system/gdbstub/CMakeLists.txt new file mode 100644 index 0000000000..06e470af47 --- /dev/null +++ b/examples/system/gdbstub/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gdbstub) \ No newline at end of file diff --git a/examples/system/gdbstub/Makefile b/examples/system/gdbstub/Makefile new file mode 100644 index 0000000000..a71a8bab1d --- /dev/null +++ b/examples/system/gdbstub/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := gdbstub + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/system/gdbstub/README.md b/examples/system/gdbstub/README.md new file mode 100644 index 0000000000..00391a3071 --- /dev/null +++ b/examples/system/gdbstub/README.md @@ -0,0 +1,127 @@ +# GDBstub example + +This example shows how to use gdbstub and it's functionality at runtime to debug an application with GDB. +With the gdbstub component it is possible to run GDB from IDF Monitor by pressing Ctrl+C and debug +the application using GDB. It is also possible to read/modify memory values, interrupt and continue the application. +Upon exit from GDB, the application will continue to work in IDF Monitor as before. + +## How to use example +### Hardware Required + +he example can run on any commonly available ESP32 development board. +There are two possible ways to execute gdbstub with GDB: from IDF Monitor and as standalone application. +gdbstub support ESP32, ESP32-S2 and ESP32-S3 chips. + +### Configure the project + +By default, the example is already pre-configured, but the user can change configuration options with the following command: +``` +idf.py menuconfig +``` +Current example is pre-configured. The user can scroll through the system parameters and see the settings. +Most important one is: +-> Component Config -> ESP System Settings -> Panic handler behaviour -> GDBStub on runtime +This selection switches gdbstub to runtime mode. +Depending on the project, following settings could be used: +-> Component Config -> GDB Stub -> ... +The user can enable or disable task list handling and define a maximum amount of tasks. +Note that gdbstub can now only be used when FreeRTOS is run on the first core only. +This setting is located here: +-> Component Config -> FreeRTOS -> Run FreeRTOS only on first core. + +### Build and Flash + +Build the project and flash it to the board, then run IDF Monitor to view the serial output: + +``` +idf.py -p PORT flash monitor +``` +Replace PORT with the name of the serial port to use, for example COM4 for Windows or /dev/ttyUSB0 for Linux. +To exit the serial monitor, type ``Ctrl-]``. +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +In addition, it is also possible to run GDB and connect to the Esp32 directly, without IDF Monitor. +``` +xtensa-esp32-elf-gdb ./build/gdbstub.elf -ex "set serial baud 115200" -ex "target remote \\.\COM10" +``` +This will execute GDB and GDB will connect to your Esp32 by serial port COM10 with baudrate 115200. + +## Example Output + +The example demonstrates how to switch to GDB, watch values, change values, continue to run, and exit from GDB to the application. +To switch to GDB, the user presses Ctrl+C. This will stop the application and run the GDB. +In GDB, the user can print values "print call_count" and "print update_log_level" and then +change them "set call_count 100" and "set update_log_level = ESP_LOG_WARN". +The user can continue running the application in GDB by entering "continue" and then interrupt the application by pressing Ctrl+C. +The user can check again that the application has worked by checking variable "print call_count". +The user can exit from GDB to continue seeing the trace from IDF Monitor by pressing "quit" and then "y". +The user will see in IDF Monitor that call_count and logging level have changed. +A typical console output for such a scenario is shown below: +``` +I (300) cpu_start: Starting scheduler on PRO CPU. +Hello GDB example! +I (307) gdbstub_example: INFO mode enabled. Call - 0. To enter GDB please press "Ctrl+C" +W (317) gdbstub_example: WARN mode enabled. Call - 0. To enter GDB please press "Ctrl+C" +I (1317) gdbstub_example: INFO mode enabled. Call - 1. To enter GDB please press "Ctrl+C" +W (1317) gdbstub_example: WARN mode enabled. Call - 1. To enter GDB please press "Ctrl+C" +To exit from the idf.py please use "Ctrl+]" +$T02#b6GNU gdb (crosstool-NG esp-2020r3) 8.1.0.20180627-git +Copyright (C) 2018 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. Type "show copying" +and "show warranty" for details. +This GDB was configured as "--host=x86_64-host_w64-mingw32 --target=xtensa-esp32-elf". +Type "show configuration" for configuration details. +For bug reporting instructions, please see: +. +Find the GDB manual and other documentation resources online at: +. +For help, type "help". +Type "apropos word" to search for commands related to "word"... +Reading symbols from c:\esp-idf\examples\system\gdbstub\build\gdbstub.elf...done. +Remote debugging using \\.\COM15 +0x400dff0a in esp_pm_impl_waiti () at C:/esp-idf/components/esp_pm/pm_impl.c:533 +533 asm("waiti 0"); +(gdb) print call_count +$1 = 2 +(gdb) set call_count = 100 +(gdb) print call_count +$2 = 100 +(gdb) print update_log_level +$3 = ESP_LOG_DEBUG +(gdb) set update_log_level = ESP_LOG_WARN +(gdb) print update_log_level +$4 = ESP_LOG_WARN +(gdb) c +Continuing. + +Thread 1 received signal SIGINT, Interrupt. +0x400dff0a in esp_pm_impl_waiti () at C:/esp-idf/components/esp_pm/pm_impl.c:533 +533 asm("waiti 0"); +(gdb) print call_count +$6 = 108 +(gdb) quit +A debugging session is active. + + Inferior 1 [Remote target] will be killed. + +Quit anyway? (y or n) y +W (13977) gdbstub_example: WARN mode enabled. Call - 108. To enter GDB please press "Ctrl+C" +W (14977) gdbstub_example: WARN mode enabled. Call - 109. To enter GDB please press "Ctrl+C" +W (15977) gdbstub_example: WARN mode enabled. Call - 110. To enter GDB please press "Ctrl+C" +W (16977) gdbstub_example: WARN mode enabled. Call - 111. To enter GDB please press "Ctrl+C" +``` + +To reproduce this scenario run the application by: idf.py -P PORT flash monitor +Then: +1. Interrupt the application by pressing Ctrl+C +2. In GDB, print the application values by typing in GDB command line "print call_count" or "print update_log_level" +3. Modify the application values by typing in GDB command line "set call_count = 100" or "set update_log_level = ESP_LOG_WARN" +4. Continue the application by typing in GDB command line "continue" +5. Interrupt application by pressing Ctrl+C +6. Check the value by typing in GDB command line "print call_count" or "print update_log_level" +7. Exit GDB by typing "quit" and then "y" + +To exit from monitor please use Ctrl+] + diff --git a/examples/system/gdbstub/main/CMakeLists.txt b/examples/system/gdbstub/main/CMakeLists.txt new file mode 100644 index 0000000000..7e624c9c17 --- /dev/null +++ b/examples/system/gdbstub/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gdbstub_main.c" + INCLUDE_DIRS "") \ No newline at end of file diff --git a/examples/system/gdbstub/main/component.mk b/examples/system/gdbstub/main/component.mk new file mode 100644 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/system/gdbstub/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/system/gdbstub/main/gdbstub_main.c b/examples/system/gdbstub/main/gdbstub_main.c new file mode 100644 index 0000000000..0884a7757b --- /dev/null +++ b/examples/system/gdbstub/main/gdbstub_main.c @@ -0,0 +1,39 @@ +/* Hello World Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_log.h" + + +int call_count = 0; + +static const char *TAG = "gdbstub_example"; +esp_log_level_t log_level = ESP_LOG_DEBUG; +esp_log_level_t update_log_level = ESP_LOG_DEBUG; + +void app_main(void) +{ + printf("Hello GDB example!\n"); + + call_count = 0; + + for (;;) { + ESP_LOGD(TAG, "DEBUG mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count); + ESP_LOGI(TAG, "INFO mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count); + ESP_LOGW(TAG, "WARN mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count++); + if (update_log_level != log_level) { + log_level = update_log_level; + esp_log_level_set(TAG, log_level); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} diff --git a/examples/system/gdbstub/sdkconfig.defaults b/examples/system/gdbstub/sdkconfig.defaults new file mode 100644 index 0000000000..e679222122 --- /dev/null +++ b/examples/system/gdbstub/sdkconfig.defaults @@ -0,0 +1,22 @@ +# +# GDB Stub +# +CONFIG_ESP_GDBSTUB_ENABLED=y +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y +CONFIG_ESP_GDBSTUB_MAX_TASKS=32 +# end of GDB Stub + +# +# FreeRTOS +# +CONFIG_FREERTOS_UNICORE=y + +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +# CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y +CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y +# end of ESP System Settings \ No newline at end of file From c6e3eb0922736b4d65e93ec30196625f4d81140c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Apr 2021 10:54:15 +0300 Subject: [PATCH 2/5] idf.py.exe changes to handle Ctrl+C in correct way. Handling Ctrl+C in correct way for gdbstubs. --- tools/idf.py | 12 ++++++++++++ tools/windows/idf_exe/idf_main.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/tools/idf.py b/tools/idf.py index 4e296c58aa..273eb24766 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -39,6 +39,9 @@ from collections import Counter, OrderedDict from importlib import import_module from pkgutil import iter_modules +import signal + + # pyc files remain in the filesystem when switching between branches which might raise errors for incompatible # idf.py extensions. Therefore, pyc file generation is turned off: sys.dont_write_bytecode = True @@ -723,7 +726,16 @@ def init_cli(verbose_output=None): return CLI(help=cli_help, verbose_output=verbose_output, all_actions=all_actions) +def signal_handler(signal, frame): + # The Ctrl+C processed by other threads inside + pass + + def main(): + + # Processing of Ctrl+C event for all threads made by main() + signal.signal(signal.SIGINT, signal_handler) + checks_output = check_environment() cli = init_cli(verbose_output=checks_output) # the argument `prog_name` must contain name of the file - not the absolute path to it! diff --git a/tools/windows/idf_exe/idf_main.c b/tools/windows/idf_exe/idf_main.c index cbfcf7990f..dbbe267305 100644 --- a/tools/windows/idf_exe/idf_main.c +++ b/tools/windows/idf_exe/idf_main.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #define LINESIZE 1024 @@ -43,6 +46,17 @@ BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) } } +BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) { + // Handle the CTRL-C signal. + case CTRL_C_EVENT: + return TRUE; + default: + return FALSE; + } +} + int main(int argc, LPTSTR argv[]) { /* Print the version of this wrapper tool, but only if invoked as "idf.exe". From a16ae6c73741f01b2458faaa890eed7b8f3d36cc Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 16 Apr 2021 13:59:50 +0300 Subject: [PATCH 3/5] IDF monitor update --- tools/idf_monitor.py | 113 +++++++++++++++++------- tools/idf_monitor_base/serial_reader.py | 24 ++++- 2 files changed, 104 insertions(+), 33 deletions(-) diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index e1a9164b5c..465db7ad32 100755 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -140,6 +140,8 @@ class Monitor(object): self._decode_panic = decode_panic self._reading_panic = PANIC_IDLE self._panic_buffer = b'' + self.gdb_exit = False + self.start_cmd_sent = False def invoke_processing_last_line(self): # type: () -> None @@ -149,43 +151,70 @@ class Monitor(object): # type: () -> None self.console_reader.start() self.serial_reader.start() + self.gdb_exit = False + self.start_cmd_sent = False try: while self.console_reader.alive and self.serial_reader.alive: try: - item = self.cmd_queue.get_nowait() - except queue.Empty: - try: - item = self.event_queue.get(True, 0.03) - except queue.Empty: - continue + if self.gdb_exit is True: + self.gdb_exit = False + + time.sleep(0.3) + try: + # Continue the program after exit from the GDB + self.serial.write(codecs.encode('+$c#63')) + self.start_cmd_sent = True + except serial.SerialException: + pass # this shouldn't happen, but sometimes port has closed in serial thread + except UnicodeEncodeError: + pass # this can happen if a non-ascii character was passed, ignoring - event_tag, data = item - if event_tag == TAG_CMD: - self.handle_commands(data, self.target) - elif event_tag == TAG_KEY: try: - self.serial.write(codecs.encode(data)) + item = self.cmd_queue.get_nowait() + except queue.Empty: + try: + item = self.event_queue.get(True, 0.03) + except queue.Empty: + continue + + (event_tag, data) = item + + if event_tag == TAG_CMD: + self.handle_commands(data, self.target) + elif event_tag == TAG_KEY: + try: + self.serial.write(codecs.encode(data)) + except serial.SerialException: + pass # this shouldn't happen, but sometimes port has closed in serial thread + except UnicodeEncodeError: + pass # this can happen if a non-ascii character was passed, ignoring + elif event_tag == TAG_SERIAL: + self.handle_serial_input(data) + if self._invoke_processing_last_line_timer is not None: + self._invoke_processing_last_line_timer.cancel() + self._invoke_processing_last_line_timer = threading.Timer(0.1, self.invoke_processing_last_line) + self._invoke_processing_last_line_timer.start() + # If no futher data is received in the next short period + # of time then the _invoke_processing_last_line_timer + # generates an event which will result in the finishing of + # the last line. This is fix for handling lines sent + # without EOL. + elif event_tag == TAG_SERIAL_FLUSH: + self.handle_serial_input(data, finalize_line=True) + else: + raise RuntimeError("Bad event data %r" % ((event_tag,data),)) + except KeyboardInterrupt: + try: + yellow_print("To exit from IDF monitor please use \"Ctrl+]\"") + self.serial.write(codecs.encode('\x03')) except serial.SerialException: pass # this shouldn't happen, but sometimes port has closed in serial thread except UnicodeEncodeError: pass # this can happen if a non-ascii character was passed, ignoring - elif event_tag == TAG_SERIAL: - self.handle_serial_input(data) - if self._invoke_processing_last_line_timer is not None: - self._invoke_processing_last_line_timer.cancel() - self._invoke_processing_last_line_timer = threading.Timer(0.1, self.invoke_processing_last_line) - self._invoke_processing_last_line_timer.start() - # If no further data is received in the next short period - # of time then the _invoke_processing_last_line_timer - # generates an event which will result in the finishing of - # the last line. This is fix for handling lines sent - # without EOL. - elif event_tag == TAG_SERIAL_FLUSH: - self.handle_serial_input(data, finalize_line=True) - else: - raise RuntimeError('Bad event data %r' % ((event_tag, data),)) except SerialStopException: normal_print('Stopping condition has been received\n') + except KeyboardInterrupt: + pass finally: try: self.console_reader.stop() @@ -200,6 +229,13 @@ class Monitor(object): def handle_serial_input(self, data, finalize_line=False): # type: (bytes, bool) -> None + # Remove "+" after Continue command + if self.start_cmd_sent is True: + self.start_cmd_sent = False + pos = data.find(b"+") + if pos != -1: + data = data[1:] + sp = data.split(b'\n') if self._last_line_part != b'': # add unprocessed part from previous "data" to the first line @@ -260,6 +296,7 @@ class Monitor(object): def __exit__(self, *args, **kwargs): # type: ignore """ Use 'with self' to temporarily disable monitoring behaviour """ self.console_reader.start() + self.serial_reader.gdb_exit = self.gdb_exit # write gdb_exit flag self.serial_reader.start() def prompt_next_action(self, reason): # type: (str) -> None @@ -480,10 +517,25 @@ class Monitor(object): cmd = ['%sgdb' % self.toolchain_prefix, '-ex', 'set serial baud %d' % self.serial.baudrate, '-ex', 'target remote %s' % self.serial.port, - '-ex', 'interrupt', # monitor has already parsed the first 'reason' command, need a second self.elf_file] - process = subprocess.Popen(cmd, cwd='.') - process.wait() + + # Here we handling GDB as a process + if True: + # Open GDB process + try: + process = subprocess.Popen(cmd, cwd=".") + except KeyboardInterrupt: + pass + + # We ignore Ctrl+C interrupt form external process abd wait responce util GDB will be finished. + while True: + try: + process.wait() + break + except KeyboardInterrupt: + pass # We ignore the Ctrl+C + self.gdb_exit = True + except OSError as e: red_print('%s: %s' % (' '.join(cmd), e)) except KeyboardInterrupt: @@ -499,7 +551,6 @@ class Monitor(object): subprocess.call(['stty', 'sane']) except Exception: pass # don't care if there's no stty, we tried... - self.prompt_next_action('gdb exited') def output_enable(self, enable): # type: (bool) -> None self._output_enabled = enable @@ -733,6 +784,8 @@ def main(): # type: () -> None yellow_print('--- Print filter: {} ---'.format(args.print_filter)) monitor.main_loop() + except KeyboardInterrupt: + pass finally: if ws: ws.close() diff --git a/tools/idf_monitor_base/serial_reader.py b/tools/idf_monitor_base/serial_reader.py index 29e26860b0..c3b7a60bf0 100644 --- a/tools/idf_monitor_base/serial_reader.py +++ b/tools/idf_monitor_base/serial_reader.py @@ -38,6 +38,7 @@ class SerialReader(StoppableThread): self.baud = serial_instance.baudrate self.serial = serial_instance self.event_queue = event_queue + self.gdb_exit = False if not hasattr(self.serial, 'cancel_read'): # enable timeout for checking alive flag, # if cancel_read not available @@ -47,10 +48,27 @@ class SerialReader(StoppableThread): # type: () -> None if not self.serial.is_open: self.serial.baudrate = self.baud - self.serial.rts = True # Force an RTS reset on open + # We can come to this thread at startup or from external application line GDB. + # If we come from GDB we would like to continue to run without reset. + if self.gdb_exit is False: + # This sequence of DTR/RTS and open/close set the serial port to + # condition when GDB not make reset of the target by switching DTR/RTS. + self.serial.rts = True # IO0=LOW + self.serial.dtr = self.serial.dtr # usbser.sys workaround + self.serial.open() + self.serial.close() + self.serial.rts = False # IO0=HIGH + self.serial.dtr = False + else: # if we exit from GDB, we don't need to reset the target + self.serial.rts = False + self.serial.dtr = True + + # Current state not reset the target! + self.gdb_exit = False self.serial.open() - self.serial.rts = False - self.serial.dtr = self.serial.dtr # usbser.sys workaround + time.sleep(0.005) # Add a delay to meet the requirements of minimal EN low time (2ms for ESP32-C3) + self.serial.rts = False # Set rts/dtr to the working state + self.serial.dtr = self.serial.dtr # usbser.sys workaround try: while self.alive: try: From f8197c244652abd9b1488aec9f8245b2a62692c8 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 16 Apr 2021 13:59:37 +0300 Subject: [PATCH 4/5] Fix problem with panic handler with gdbstubs. --- components/esp_gdbstub/include/esp_gdbstub.h | 1 + .../private_include/esp_gdbstub_common.h | 1 + components/esp_gdbstub/src/gdbstub.c | 3 +- .../esp_gdbstub/xtensa/esp_gdbstub_arch.h | 1 - components/esp_system/panic.c | 93 +++++++------------ 5 files changed, 38 insertions(+), 61 deletions(-) diff --git a/components/esp_gdbstub/include/esp_gdbstub.h b/components/esp_gdbstub/include/esp_gdbstub.h index d896e77ffc..f1e7921de6 100644 --- a/components/esp_gdbstub/include/esp_gdbstub.h +++ b/components/esp_gdbstub/include/esp_gdbstub.h @@ -19,6 +19,7 @@ extern "C" { #endif void esp_gdbstub_init(void); +void esp_gdbstub_panic_handler(void *frame); #ifdef __cplusplus } diff --git a/components/esp_gdbstub/private_include/esp_gdbstub_common.h b/components/esp_gdbstub/private_include/esp_gdbstub_common.h index cb3d341c32..d9f261c9d2 100644 --- a/components/esp_gdbstub/private_include/esp_gdbstub_common.h +++ b/components/esp_gdbstub/private_include/esp_gdbstub_common.h @@ -18,6 +18,7 @@ #include #include +#include "gdbstub_target_config.h" #include "esp_gdbstub_arch.h" #include "sdkconfig.h" diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index b58fec135e..993d5e9e6b 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -45,8 +45,9 @@ static esp_gdbstub_gdb_regfile_t *gdb_local_regfile = &s_scratch.regfile; /** * @breef panic handler */ -void esp_gdbstub_panic_handler(esp_gdbstub_frame_t *frame) +void esp_gdbstub_panic_handler(void *in_frame) { + esp_gdbstub_frame_t* frame = (esp_gdbstub_frame_t*)in_frame; #ifndef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS esp_gdbstub_frame_to_regfile(frame, &s_scratch.regfile); #else diff --git a/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h index 18b119cb3f..4730e0a124 100644 --- a/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h +++ b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h @@ -15,7 +15,6 @@ #pragma once #include #include "freertos/xtensa_context.h" -#include "gdbstub_target_config.h" #ifdef __cplusplus extern "C" { diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index baa14dba80..7a55653a38 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -30,7 +30,6 @@ #include "esp_private/panic_internal.h" #include "port/panic_funcs.h" -#include "esp_rom_sys.h" #include "sdkconfig.h" @@ -59,10 +58,6 @@ #include "esp_gdbstub.h" #endif -#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG -#include "hal/usb_serial_jtag_ll.h" -#endif - bool g_panic_abort = false; static char *s_panic_abort_details = NULL; @@ -73,13 +68,13 @@ static wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1 #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT #if CONFIG_ESP_CONSOLE_UART -static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 :&UART1 }; +static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 : &UART1 }; void panic_print_char(const char c) { uint32_t sz = 0; - while (!uart_hal_get_txfifo_len(&s_panic_uart)); - uart_hal_write_txfifo(&s_panic_uart, (uint8_t *) &c, 1, &sz); + while(!uart_hal_get_txfifo_len(&s_panic_uart)); + uart_hal_write_txfifo(&s_panic_uart, (uint8_t*) &c, 1, &sz); } #endif // CONFIG_ESP_CONSOLE_UART @@ -92,27 +87,6 @@ void panic_print_char(const char c) } #endif // CONFIG_ESP_CONSOLE_USB_CDC -#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG -//Timeout; if there's no host listening, the txfifo won't ever -//be writable after the first packet. - -#define USBSERIAL_TIMEOUT_MAX_US 50000 -static int s_usbserial_timeout = 0; - -void panic_print_char(const char c) -{ - while (!usb_serial_jtag_ll_txfifo_writable() && s_usbserial_timeout < (USBSERIAL_TIMEOUT_MAX_US / 100)) { - esp_rom_delay_us(100); - s_usbserial_timeout++; - } - if (usb_serial_jtag_ll_txfifo_writable()) { - usb_serial_jtag_ll_write_txfifo((const uint8_t *)&c, 1); - s_usbserial_timeout = 0; - } -} -#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG - - #if CONFIG_ESP_CONSOLE_NONE void panic_print_char(const char c) { @@ -122,7 +96,7 @@ void panic_print_char(const char c) void panic_print_str(const char *str) { - for (int i = 0; str[i] != 0; i++) { + for(int i = 0; str[i] != 0; i++) { panic_print_char(str[i]); } } @@ -171,7 +145,7 @@ static void reconfigure_all_wdts(void) //Reconfigure TWDT (Timer Group 0) wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT0_TICK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US wdt_hal_write_protect_disable(&wdt0_context); - wdt_hal_config_stage(&wdt0_context, 0, 1000 * 1000 / MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset + wdt_hal_config_stage(&wdt0_context, 0, 1000*1000/MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset wdt_hal_enable(&wdt0_context); wdt_hal_write_protect_enable(&wdt0_context); @@ -216,29 +190,29 @@ void esp_panic_handler(panic_info_t *info) info->exception = PANIC_EXCEPTION_ABORT; } - /* - * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: - * - * - * Guru Meditation Error: Core (). - *
- * - * - * - * - * - * - * ---------------------------------------------------------------------------------------- - * core - core where exception was triggered - * exception - what kind of exception occured - * description - a short description regarding the exception that occured - * details - more details about the exception - * state - processor state like register contents, and backtrace - * elf_info - details about the image currently running - * - * NULL fields in panic_info_t are not printed. - * - * */ + /* + * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: + * + * + * Guru Meditation Error: Core (). + *
+ * + * + * + * + * + * + * ---------------------------------------------------------------------------------------- + * core - core where exception was triggered + * exception - what kind of exception occured + * description - a short description regarding the exception that occured + * details - more details about the exception + * state - processor state like register contents, and backtrace + * elf_info - details about the image currently running + * + * NULL fields in panic_info_t are not printed. + * + * */ if (info->reason) { panic_print_str("Guru Meditation Error: Core "); panic_print_dec(info->core); @@ -322,7 +296,7 @@ void esp_panic_handler(panic_info_t *info) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); panic_print_str("Entering gdb stub now.\r\n"); - esp_gdbstub_panic_handler((esp_gdbstub_frame_t *)info->frame); + esp_gdbstub_panic_handler(info->frame); #else #if CONFIG_ESP_COREDUMP_ENABLE static bool s_dumping_core; @@ -347,7 +321,8 @@ void esp_panic_handler(panic_info_t *info) #if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { - switch (info->exception) { + switch (info->exception) + { case PANIC_EXCEPTION_IWDT: esp_reset_reason_set_hint(ESP_RST_INT_WDT); break; @@ -373,10 +348,10 @@ void esp_panic_handler(panic_info_t *info) } -void __attribute__((noreturn,no_sanitize_undefined)) panic_abort(const char *details) +void __attribute__((noreturn)) panic_abort(const char *details) { g_panic_abort = true; - s_panic_abort_details = (char *) details; + s_panic_abort_details = (char*) details; #if CONFIG_APPTRACE_ENABLE #if CONFIG_SYSVIEW_ENABLE @@ -388,7 +363,7 @@ void __attribute__((noreturn,no_sanitize_undefined)) panic_abort(const char *det #endif *((int *) 0) = 0; // NOLINT(clang-analyzer-core.NullDereference) should be an invalid operation on targets - while (1); + while(1); } /* Weak versions of reset reason hint functions. From 00a7ecb5a319a3901f3861f6c6ce3edc67bc3c1f Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 19 Apr 2021 12:03:43 +0300 Subject: [PATCH 5/5] Code cleanup. Bugfix after rebase with master. Formating. --- components/esp_gdbstub/CMakeLists.txt | 25 +++-- components/esp_gdbstub/component.mk | 2 +- components/esp_gdbstub/esp32/gdbstub_esp32.c | 18 ---- .../esp_gdbstub/esp32s2/gdbstub_esp32s2.c | 18 ---- .../esp_gdbstub/esp32s3/gdbstub_esp32s3.c | 19 ---- .../esp_gdbstub/esp_common/gdbstub_common.c | 6 +- components/esp_gdbstub/riscv/gdbstub_riscv.c | 5 + components/esp_gdbstub/src/gdbstub.c | 47 ++-------- .../esp_gdbstub/xtensa/esp_gdbstub_arch.h | 1 + components/esp_gdbstub/xtensa/gdbstub-entry.S | 1 - components/esp_system/panic.c | 93 ++++++++++++------- components/freertos/port/port_common.c | 8 ++ docs/en/api-guides/tools/idf-monitor.rst | 6 +- .../hello_world/main/CMakeLists.txt | 2 +- examples/system/gdbstub/CMakeLists.txt | 2 +- examples/system/gdbstub/Makefile | 1 - examples/system/gdbstub/main/CMakeLists.txt | 2 +- examples/system/gdbstub/main/component.mk | 1 - examples/system/gdbstub/sdkconfig.defaults | 2 +- tools/idf.py | 6 +- tools/idf_monitor.py | 35 ++++--- tools/idf_monitor_base/serial_reader.py | 10 +- tools/windows/idf_exe/idf_main.c | 14 --- 23 files changed, 130 insertions(+), 194 deletions(-) delete mode 100644 components/esp_gdbstub/esp32/gdbstub_esp32.c delete mode 100644 components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c delete mode 100644 components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c diff --git a/components/esp_gdbstub/CMakeLists.txt b/components/esp_gdbstub/CMakeLists.txt index cb799481b3..797448b10a 100644 --- a/components/esp_gdbstub/CMakeLists.txt +++ b/components/esp_gdbstub/CMakeLists.txt @@ -1,15 +1,20 @@ idf_build_get_property(target IDF_TARGET) -set(esp_gdbstub_srcs "src/gdbstub.c" - "src/packet.c" - "esp_common/gdbstub_common.c" - "${target}/gdbstub_${target}.c" - "xtensa/gdbstub-entry.S" - "xtensa/gdbstub_xtensa.c") - -idf_component_register(SRCS "${esp_gdbstub_srcs}" +idf_component_register(SRCS "src/gdbstub.c" "src/packet.c" INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "private_include" "${target}" "xtensa" + PRIV_INCLUDE_DIRS "private_include" LDFRAGMENTS "linker.lf" REQUIRES "freertos" - PRIV_REQUIRES "soc" "xtensa" "esp_rom") + PRIV_REQUIRES "soc" "esp_rom") + +if(CONFIG_IDF_TARGET_ARCH_XTENSA) + target_include_directories(${COMPONENT_LIB} PUBLIC "xtensa" "${target}") + target_sources(${COMPONENT_LIB} PRIVATE "xtensa/gdbstub_xtensa.c" + "xtensa/gdbstub-entry.S" + "esp_common/gdbstub_common.c") + +elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + target_include_directories(${COMPONENT_LIB} PUBLIC "riscv" "${target}") + target_sources(${COMPONENT_LIB} PRIVATE "riscv/gdbstub_riscv.c" + "${target}/gdbstub_${target}.c") +endif() diff --git a/components/esp_gdbstub/component.mk b/components/esp_gdbstub/component.mk index 97dfce265f..91e522594d 100644 --- a/components/esp_gdbstub/component.mk +++ b/components/esp_gdbstub/component.mk @@ -1,4 +1,4 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := private_include esp32 xtensa -COMPONENT_SRCDIRS := src esp32 xtensa +COMPONENT_SRCDIRS := src esp32 xtensa esp_common COMPONENT_ADD_LDFRAGMENTS += linker.lf diff --git a/components/esp_gdbstub/esp32/gdbstub_esp32.c b/components/esp_gdbstub/esp32/gdbstub_esp32.c deleted file mode 100644 index 39fde0a6c7..0000000000 --- a/components/esp_gdbstub/esp32/gdbstub_esp32.c +++ /dev/null @@ -1,18 +0,0 @@ -// 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" diff --git a/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c b/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c deleted file mode 100644 index 39fde0a6c7..0000000000 --- a/components/esp_gdbstub/esp32s2/gdbstub_esp32s2.c +++ /dev/null @@ -1,18 +0,0 @@ -// 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" diff --git a/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c b/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c deleted file mode 100644 index 1e02fec0d0..0000000000 --- a/components/esp_gdbstub/esp32s3/gdbstub_esp32s3.c +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2020 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 "sdkconfig.h" -#include "soc/uart_periph.h" -#include "soc/gpio_periph.h" -#include "esp_gdbstub_common.h" - diff --git a/components/esp_gdbstub/esp_common/gdbstub_common.c b/components/esp_gdbstub/esp_common/gdbstub_common.c index 23ff278a2c..2cf908fea7 100644 --- a/components/esp_gdbstub/esp_common/gdbstub_common.c +++ b/components/esp_gdbstub/esp_common/gdbstub_common.c @@ -29,12 +29,16 @@ void esp_gdbstub_target_init(void) case 0: gdb_uart = &UART0; break; +#if SOC_UART_NUM > 1 case 1: gdb_uart = &UART1; break; +#endif +#if SOC_UART_NUM > 2 case 2: gdb_uart = &UART2; break; +#endif default: gdb_uart = &UART0; break; @@ -126,4 +130,4 @@ int esp_gdbstub_writemem(unsigned int addr, unsigned char data) asm volatile("ISYNC\nISYNC\n"); return 0; -} \ No newline at end of file +} diff --git a/components/esp_gdbstub/riscv/gdbstub_riscv.c b/components/esp_gdbstub/riscv/gdbstub_riscv.c index 7cded48a34..ad99f5c64f 100644 --- a/components/esp_gdbstub/riscv/gdbstub_riscv.c +++ b/components/esp_gdbstub/riscv/gdbstub_riscv.c @@ -58,3 +58,8 @@ int esp_gdbstub_get_signal(const esp_gdbstub_frame_t *frame) { return 5; // SIGTRAP, see IDF-2490 } + +void _xt_gdbstub_int(void * frame) +{ + +} diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index 993d5e9e6b..1361a64e73 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -24,7 +24,6 @@ #include "hal/wdt_hal.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -//#include "esp_task_wdt.h" #ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS @@ -43,11 +42,11 @@ static esp_gdbstub_scratch_t s_scratch; static esp_gdbstub_gdb_regfile_t *gdb_local_regfile = &s_scratch.regfile; /** - * @breef panic handler + * @brief panic handler */ void esp_gdbstub_panic_handler(void *in_frame) { - esp_gdbstub_frame_t* frame = (esp_gdbstub_frame_t*)in_frame; + esp_gdbstub_frame_t *frame = (esp_gdbstub_frame_t *)in_frame; #ifndef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS esp_gdbstub_frame_to_regfile(frame, &s_scratch.regfile); #else @@ -186,7 +185,7 @@ static inline void enable_all_wdts(void) * @param curr_regs - actual registers frame * */ -void gdbstub_handle_uart_int(XtExcFrame *regs_frame) +void gdbstub_handle_uart_int(esp_gdbstub_frame_t *regs_frame) { // Disable all enabled WDT on enter disable_all_wdts(); @@ -234,7 +233,7 @@ intr_handle_t intr_handle_; extern void _xt_gdbstub_int(void * ); #ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME -/** @breef Init gdbstub +/** @brief Init gdbstub * Init uart interrupt for gdbstub * */ void esp_gdbstub_init(void) @@ -395,18 +394,6 @@ static bool get_task_handle(size_t index, TaskHandle_t *handle) return true; } -static eTaskState get_task_state(size_t index) -{ - return eSuspended; -// return s_scratch.tasks[index].eCurrentState; -} - -static int get_task_cpu_id(size_t index) -{ - return 0; - // return s_scratch.tasks[index].xCoreID; -} - /** Get the index of the task running on the current CPU, and save the result */ static void find_paniced_task_index(void) { @@ -531,29 +518,8 @@ static void handle_qThreadExtraInfo_command(const unsigned char *cmd, int len) esp_gdbstub_send_str_as_hex((const char *)pcTaskGetTaskName(handle)); esp_gdbstub_send_hex(' ', 8); - eTaskState state = get_task_state(task_index); - switch (state) { - case eRunning: - esp_gdbstub_send_str_as_hex("State: Running "); - esp_gdbstub_send_str_as_hex("@CPU"); - esp_gdbstub_send_hex(get_task_cpu_id(task_index) + '0', 8); - break; - case eReady: - esp_gdbstub_send_str_as_hex("State: Ready"); - break; - case eBlocked: - esp_gdbstub_send_str_as_hex("State: Blocked"); - break; - case eSuspended: - esp_gdbstub_send_str_as_hex("State: Suspended"); - break; - case eDeleted: - esp_gdbstub_send_str_as_hex("State: Deleted"); - break; - default: - esp_gdbstub_send_str_as_hex("State: Invalid"); - break; - } + // Current version report only Suspended state + esp_gdbstub_send_str_as_hex("State: Suspended"); esp_gdbstub_send_end(); } @@ -605,4 +571,3 @@ static int handle_task_commands(unsigned char *cmd, int len) } #endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS - diff --git a/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h index 4730e0a124..18b119cb3f 100644 --- a/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h +++ b/components/esp_gdbstub/xtensa/esp_gdbstub_arch.h @@ -15,6 +15,7 @@ #pragma once #include #include "freertos/xtensa_context.h" +#include "gdbstub_target_config.h" #ifdef __cplusplus extern "C" { diff --git a/components/esp_gdbstub/xtensa/gdbstub-entry.S b/components/esp_gdbstub/xtensa/gdbstub-entry.S index 780eed9967..c73e419897 100644 --- a/components/esp_gdbstub/xtensa/gdbstub-entry.S +++ b/components/esp_gdbstub/xtensa/gdbstub-entry.S @@ -41,4 +41,3 @@ _xt_gdbstub_int: mov a6,sp call0 gdbstub_handle_uart_int ret - diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index 7a55653a38..58629dd5ca 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -30,6 +30,7 @@ #include "esp_private/panic_internal.h" #include "port/panic_funcs.h" +#include "esp_rom_sys.h" #include "sdkconfig.h" @@ -58,6 +59,10 @@ #include "esp_gdbstub.h" #endif +#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +#include "hal/usb_serial_jtag_ll.h" +#endif + bool g_panic_abort = false; static char *s_panic_abort_details = NULL; @@ -68,13 +73,13 @@ static wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1 #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT #if CONFIG_ESP_CONSOLE_UART -static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 : &UART1 }; +static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 :&UART1 }; void panic_print_char(const char c) { uint32_t sz = 0; - while(!uart_hal_get_txfifo_len(&s_panic_uart)); - uart_hal_write_txfifo(&s_panic_uart, (uint8_t*) &c, 1, &sz); + while (!uart_hal_get_txfifo_len(&s_panic_uart)); + uart_hal_write_txfifo(&s_panic_uart, (uint8_t *) &c, 1, &sz); } #endif // CONFIG_ESP_CONSOLE_UART @@ -87,6 +92,27 @@ void panic_print_char(const char c) } #endif // CONFIG_ESP_CONSOLE_USB_CDC +#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +//Timeout; if there's no host listening, the txfifo won't ever +//be writable after the first packet. + +#define USBSERIAL_TIMEOUT_MAX_US 50000 +static int s_usbserial_timeout = 0; + +void panic_print_char(const char c) +{ + while (!usb_serial_jtag_ll_txfifo_writable() && s_usbserial_timeout < (USBSERIAL_TIMEOUT_MAX_US / 100)) { + esp_rom_delay_us(100); + s_usbserial_timeout++; + } + if (usb_serial_jtag_ll_txfifo_writable()) { + usb_serial_jtag_ll_write_txfifo((const uint8_t *)&c, 1); + s_usbserial_timeout = 0; + } +} +#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + + #if CONFIG_ESP_CONSOLE_NONE void panic_print_char(const char c) { @@ -96,7 +122,7 @@ void panic_print_char(const char c) void panic_print_str(const char *str) { - for(int i = 0; str[i] != 0; i++) { + for (int i = 0; str[i] != 0; i++) { panic_print_char(str[i]); } } @@ -145,7 +171,7 @@ static void reconfigure_all_wdts(void) //Reconfigure TWDT (Timer Group 0) wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT0_TICK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US wdt_hal_write_protect_disable(&wdt0_context); - wdt_hal_config_stage(&wdt0_context, 0, 1000*1000/MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset + wdt_hal_config_stage(&wdt0_context, 0, 1000 * 1000 / MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset wdt_hal_enable(&wdt0_context); wdt_hal_write_protect_enable(&wdt0_context); @@ -190,29 +216,29 @@ void esp_panic_handler(panic_info_t *info) info->exception = PANIC_EXCEPTION_ABORT; } - /* - * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: - * - * - * Guru Meditation Error: Core (). - *
- * - * - * - * - * - * - * ---------------------------------------------------------------------------------------- - * core - core where exception was triggered - * exception - what kind of exception occured - * description - a short description regarding the exception that occured - * details - more details about the exception - * state - processor state like register contents, and backtrace - * elf_info - details about the image currently running - * - * NULL fields in panic_info_t are not printed. - * - * */ + /* + * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: + * + * + * Guru Meditation Error: Core (). + *
+ * + * + * + * + * + * + * ---------------------------------------------------------------------------------------- + * core - core where exception was triggered + * exception - what kind of exception occured + * description - a short description regarding the exception that occured + * details - more details about the exception + * state - processor state like register contents, and backtrace + * elf_info - details about the image currently running + * + * NULL fields in panic_info_t are not printed. + * + * */ if (info->reason) { panic_print_str("Guru Meditation Error: Core "); panic_print_dec(info->core); @@ -296,7 +322,7 @@ void esp_panic_handler(panic_info_t *info) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); panic_print_str("Entering gdb stub now.\r\n"); - esp_gdbstub_panic_handler(info->frame); + esp_gdbstub_panic_handler((void *)info->frame); #else #if CONFIG_ESP_COREDUMP_ENABLE static bool s_dumping_core; @@ -321,8 +347,7 @@ void esp_panic_handler(panic_info_t *info) #if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { - switch (info->exception) - { + switch (info->exception) { case PANIC_EXCEPTION_IWDT: esp_reset_reason_set_hint(ESP_RST_INT_WDT); break; @@ -348,10 +373,10 @@ void esp_panic_handler(panic_info_t *info) } -void __attribute__((noreturn)) panic_abort(const char *details) +void __attribute__((noreturn, no_sanitize_undefined)) panic_abort(const char *details) { g_panic_abort = true; - s_panic_abort_details = (char*) details; + s_panic_abort_details = (char *) details; #if CONFIG_APPTRACE_ENABLE #if CONFIG_SYSVIEW_ENABLE @@ -363,7 +388,7 @@ void __attribute__((noreturn)) panic_abort(const char *details) #endif *((int *) 0) = 0; // NOLINT(clang-analyzer-core.NullDereference) should be an invalid operation on targets - while(1); + while (1); } /* Weak versions of reset reason hint functions. diff --git a/components/freertos/port/port_common.c b/components/freertos/port/port_common.c index 8a7984ea29..b6eb0bd00e 100644 --- a/components/freertos/port/port_common.c +++ b/components/freertos/port/port_common.c @@ -61,6 +61,10 @@ volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; static void main_task(void* args); +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +void esp_gdbstub_init(void); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + extern void app_main(void); void esp_startup_start_app_common(void) @@ -79,6 +83,10 @@ void esp_startup_start_app_common(void) #endif #endif +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + esp_gdbstub_init(); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); diff --git a/docs/en/api-guides/tools/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index cec09371ad..a580095a12 100644 --- a/docs/en/api-guides/tools/idf-monitor.rst +++ b/docs/en/api-guides/tools/idf-monitor.rst @@ -10,7 +10,6 @@ This tool can be launched from an IDF project by running ``idf.py monitor``. For the legacy GNU Make system, run ``make monitor``. - Keyboard Shortcuts ================== @@ -59,9 +58,9 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t * - * Ctrl+X (or X) - Exit the program - - * - Ctrl+] + * - Ctrl+C - Interrupt running application - - Pauses IDF monitor and run GDB_ project debugger to debug the application at runtime. + - Pauses IDF monitor and run GDB_ project debugger to debug the application at runtime. This requires :ref:CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME option to be enabled. Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the serial port. @@ -187,6 +186,7 @@ To decode each address, IDF Monitor runs the following command in the background Launching GDB with GDBStub ~~~~~~~~~~~~~~~~~~~~~~~~~~ + By default, if esp-idf crashes, the panic handler prints relevant registers and the stack dump (similar to the ones above) over the serial port. Then it resets the board. Furthermore, the application can be configured to run GDBStub in the background and handle the Ctrl+C event from the monitor. diff --git a/examples/get-started/hello_world/main/CMakeLists.txt b/examples/get-started/hello_world/main/CMakeLists.txt index c299e03782..07686dc8e1 100644 --- a/examples/get-started/hello_world/main/CMakeLists.txt +++ b/examples/get-started/hello_world/main/CMakeLists.txt @@ -1,2 +1,2 @@ idf_component_register(SRCS "hello_world_main.c" - INCLUDE_DIRS "") \ No newline at end of file + INCLUDE_DIRS "") diff --git a/examples/system/gdbstub/CMakeLists.txt b/examples/system/gdbstub/CMakeLists.txt index 06e470af47..9392d46b7b 100644 --- a/examples/system/gdbstub/CMakeLists.txt +++ b/examples/system/gdbstub/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(gdbstub) \ No newline at end of file +project(gdbstub) diff --git a/examples/system/gdbstub/Makefile b/examples/system/gdbstub/Makefile index a71a8bab1d..6615607b98 100644 --- a/examples/system/gdbstub/Makefile +++ b/examples/system/gdbstub/Makefile @@ -6,4 +6,3 @@ PROJECT_NAME := gdbstub include $(IDF_PATH)/make/project.mk - diff --git a/examples/system/gdbstub/main/CMakeLists.txt b/examples/system/gdbstub/main/CMakeLists.txt index 7e624c9c17..b834e836a4 100644 --- a/examples/system/gdbstub/main/CMakeLists.txt +++ b/examples/system/gdbstub/main/CMakeLists.txt @@ -1,2 +1,2 @@ idf_component_register(SRCS "gdbstub_main.c" - INCLUDE_DIRS "") \ No newline at end of file + INCLUDE_DIRS "") diff --git a/examples/system/gdbstub/main/component.mk b/examples/system/gdbstub/main/component.mk index 0b9d7585e7..a98f634eae 100644 --- a/examples/system/gdbstub/main/component.mk +++ b/examples/system/gdbstub/main/component.mk @@ -2,4 +2,3 @@ # "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) - diff --git a/examples/system/gdbstub/sdkconfig.defaults b/examples/system/gdbstub/sdkconfig.defaults index e679222122..7a32ecd7f2 100644 --- a/examples/system/gdbstub/sdkconfig.defaults +++ b/examples/system/gdbstub/sdkconfig.defaults @@ -19,4 +19,4 @@ CONFIG_FREERTOS_UNICORE=y # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y -# end of ESP System Settings \ No newline at end of file +# end of ESP System Settings diff --git a/tools/idf.py b/tools/idf.py index 273eb24766..b1323145fe 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -33,15 +33,13 @@ import json import locale import os import os.path +import signal import subprocess import sys from collections import Counter, OrderedDict from importlib import import_module from pkgutil import iter_modules -import signal - - # pyc files remain in the filesystem when switching between branches which might raise errors for incompatible # idf.py extensions. Therefore, pyc file generation is turned off: sys.dont_write_bytecode = True @@ -726,7 +724,7 @@ def init_cli(verbose_output=None): return CLI(help=cli_help, verbose_output=verbose_output, all_actions=all_actions) -def signal_handler(signal, frame): +def signal_handler(_signal, _frame): # The Ctrl+C processed by other threads inside pass diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index 465db7ad32..10a9778a08 100755 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -202,10 +202,10 @@ class Monitor(object): elif event_tag == TAG_SERIAL_FLUSH: self.handle_serial_input(data, finalize_line=True) else: - raise RuntimeError("Bad event data %r" % ((event_tag,data),)) + raise RuntimeError('Bad event data %r' % ((event_tag,data),)) except KeyboardInterrupt: try: - yellow_print("To exit from IDF monitor please use \"Ctrl+]\"") + yellow_print('To exit from IDF monitor please use \"Ctrl+]\"') self.serial.write(codecs.encode('\x03')) except serial.SerialException: pass # this shouldn't happen, but sometimes port has closed in serial thread @@ -232,9 +232,9 @@ class Monitor(object): # Remove "+" after Continue command if self.start_cmd_sent is True: self.start_cmd_sent = False - pos = data.find(b"+") + pos = data.find(b'+') if pos != -1: - data = data[1:] + data = data[(pos + 1):] sp = data.split(b'\n') if self._last_line_part != b'': @@ -520,21 +520,20 @@ class Monitor(object): self.elf_file] # Here we handling GDB as a process - if True: - # Open GDB process - try: - process = subprocess.Popen(cmd, cwd=".") - except KeyboardInterrupt: - pass + # Open GDB process + try: + process = subprocess.Popen(cmd, cwd='.') + except KeyboardInterrupt: + pass - # We ignore Ctrl+C interrupt form external process abd wait responce util GDB will be finished. - while True: - try: - process.wait() - break - except KeyboardInterrupt: - pass # We ignore the Ctrl+C - self.gdb_exit = True + # We ignore Ctrl+C interrupt form external process abd wait responce util GDB will be finished. + while True: + try: + process.wait() + break + except KeyboardInterrupt: + pass # We ignore the Ctrl+C + self.gdb_exit = True except OSError as e: red_print('%s: %s' % (' '.join(cmd), e)) diff --git a/tools/idf_monitor_base/serial_reader.py b/tools/idf_monitor_base/serial_reader.py index c3b7a60bf0..f6779e23a9 100644 --- a/tools/idf_monitor_base/serial_reader.py +++ b/tools/idf_monitor_base/serial_reader.py @@ -50,18 +50,16 @@ class SerialReader(StoppableThread): self.serial.baudrate = self.baud # We can come to this thread at startup or from external application line GDB. # If we come from GDB we would like to continue to run without reset. - if self.gdb_exit is False: + if self.gdb_exit: + self.serial.rts = False + self.serial.dtr = True + else: # if we exit from GDB, we don't need to reset the target # This sequence of DTR/RTS and open/close set the serial port to # condition when GDB not make reset of the target by switching DTR/RTS. self.serial.rts = True # IO0=LOW self.serial.dtr = self.serial.dtr # usbser.sys workaround - self.serial.open() - self.serial.close() self.serial.rts = False # IO0=HIGH self.serial.dtr = False - else: # if we exit from GDB, we don't need to reset the target - self.serial.rts = False - self.serial.dtr = True # Current state not reset the target! self.gdb_exit = False diff --git a/tools/windows/idf_exe/idf_main.c b/tools/windows/idf_exe/idf_main.c index dbbe267305..cbfcf7990f 100644 --- a/tools/windows/idf_exe/idf_main.c +++ b/tools/windows/idf_exe/idf_main.c @@ -16,9 +16,6 @@ #include #include #include -#include -#include -#include #define LINESIZE 1024 @@ -46,17 +43,6 @@ BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) } } -BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) -{ - switch (fdwCtrlType) { - // Handle the CTRL-C signal. - case CTRL_C_EVENT: - return TRUE; - default: - return FALSE; - } -} - int main(int argc, LPTSTR argv[]) { /* Print the version of this wrapper tool, but only if invoked as "idf.exe".